Skip to content

reactComponentAnnotation passes props to Fragment #686

@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

BugSomething isn't working

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions