Skip to content

reactComponentAnnotation passes props to Fragment #686

Closed
@richardasymmetric

Description

@richardasymmetric

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/nextjs

SDK Version

9.2.0

Framework Version

react@npm:19.0.0-rc-66855b96-20241106 next@npm:15.1.7 [1ff14]

Link to Sentry event

https://flowtax.sentry.io/issues/6331780118/events/99036a9409274672af8e72c6295349ba/

Reproduction Example/SDK Setup

I'm going to have a hard time creating a minimal reproduction since I'm still not entirely sure what's causing it, but I have narrowed it down. However, he's my sentry configs:

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  poweredByHeader: false,

  async headers() {
    return [
      {
        source: "/:path*",
        headers: [
          {
            key: "x-content-type-options",
            value: "nosniff",
          },
          {
            key: "X-Frame-Options",
            value: "SAMEORIGIN",
          },
        ],
      },
    ];
  },

  serverExternalPackages: [
    "@prisma",
    "knex",
    "@aws-sdk/client-s3",
    "@aws-sdk/s3-request-presigner",
  ],

  compiler: {
    removeConsole:
      process.env.NODE_ENV === "production"
        ? {
            exclude: ["error", "warn"],
          }
        : false,
  },
};

// Injected content via Sentry wizard below

import { withSentryConfig } from "@sentry/nextjs";

function wrapper(nextConfig, sentryConfig) {
  if (process.env.TURBOPACK && !process.env.VERCEL_ENV) {
    console.info("Skipping Sentry setup while TurboPack is in use in development");
    return nextConfig;
  }
  return withSentryConfig(nextConfig, sentryConfig);
}

export default wrapper(nextConfig, {

  org: org here,
  project: project here,
  sentryUrl: "https://sentry.io/",

  silent: !process.env.CI,

  widenClientFileUpload: true,

  reactComponentAnnotation: {
    enabled: true,
  },

  tunnelRoute: "/monitoring",

  hideSourceMaps: true,

  disableLogger: true,

  automaticVercelMonitors: true,
});
// sentry.client.config.ts (and .server.config)
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: "my dsn here",

  // Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.
  tracesSampleRate: 1,

  // Setting this option to true will print useful information to the console while you're setting up Sentry.
  debug: false,
});

Steps to Reproduce

I'm using catalyst ui from tailwind, which in turn uses headlessui. In my code I'm using the <Listbox> componented from catalyst:

import { Listbox, ListboxOption } from "@/components/listbox";

export function SomeOptionsMenu({value}) {
    return (
    	<Listbox
    		name="optionMenu"
    		defaultValue={value}
    		onChange={(value)=>alert(value)}
    	>
    		<ListboxOption value="opt1">Option 1</ListboxOption>
    		<ListboxOption value="opt2">Option 2</ListboxOption>
    	</Listbox>
    );
}

// And the basic Listbox/ListboxOption definitions:

// Listbox

export function Listbox<T>({
  className,
  placeholder,
  autoFocus,
  "aria-label": ariaLabel,
  "children": options,
  ...props
}: {
  "className"?: string;
  "placeholder"?: React.ReactNode;
  "autoFocus"?: boolean;
  "aria-label"?: string;
  "children"?: React.ReactNode;
} & Omit<Headless.ListboxProps<typeof Fragment, T>, "as" | "multiple">) {
  return (
    <Headless.Listbox {...props} multiple={false}>
    // ...
    </Headless.Listbox>
  )
}

export function ListboxOption<T>({
  children,
  className,
  ...props
}: { className?: string; children?: React.ReactNode } & Omit<
  Headless.ListboxOptionProps<"div", T>,
  "as" | "className"
>) {
     return (
	    <Headless.ListboxOption as={Fragment} {...props}>
	    // ...
	    </Headless.ListboxOption>
    );
}

As you can see ListboxOption is rendered as a Fragment and passes through the props, however, when reactComponentAnnotation is enabled, sentry will add data-sentry-element, data-sentry-source-file, data-sentry-component properties which seem to fail.

Expected Result

It should render without errors.

Actual Result

Error: Passing props on "Fragment"!

The current component <Listbox /> is rendering a "Fragment".
However we need to passthrough the following props:
  - data-sentry-element
  - data-sentry-source-file
  - data-sentry-component
  - data-headlessui-state

Yo...
  File "we render an actual element instead of a "Fragment"."
  File "we can forward the props onto that element."
  File "client-portal/./node_modules/@headlessui/react/dist/utils/render.js", line 1, in F
    {snip} ngth>0)throw new Error(['Passing props on "Fragment"!',"",`The current component <${a} /> is rendering a "Fragment".`,"However we need to pa {snip}
  File "client-portal/./node_modules/@headlessui/react/dist/utils/render.js", line 1, in children
    {snip} o,e,a,l,i);let y=s!=null?s:0;if(y&2){let{static:f=!1,...u}=o;if(f)return F(u,e,a,l,i)}if(y&1){let{unmount:f=!0,...u}=o;return M(f?0:1,{[0]() {snip}
  File "client-portal/./node_modules/@headlessui/react/dist/utils/render.js", line 1, in F
    {snip} })}return F(o,e,a,l,i)}function F(n,r={},e,a,s){let{as:t=e,children:l,refName:i="ref",...o}=h(n,["unmount","static"]),y=n.ref!==void 0?{[i]: {snip}
...
(7 additional frame(s) were not displayed)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions