Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Next.js + Sentry + PostHog integration hydration error #1645

Open
freeatnet opened this issue Jan 8, 2025 · 1 comment
Open

Next.js + Sentry + PostHog integration hydration error #1645

freeatnet opened this issue Jan 8, 2025 · 1 comment

Comments

@freeatnet
Copy link

Steps to reproduce:

  1. Configure a Next.js app with [email protected] as outlined in the guide (including placing posthog.init in a useEffect).
  2. Add Sentry 8.x and set up PostHog Sentry integration as outlined in the guide..

Expected: Things work :)

Observed: Next.js starts throwing a hydration error. Specifically, [email protected] will log a warning stating "Prop dangerouslySetInnerHTML did not match", while [email protected] will log "A tree hydrated but some attributes of the server-rendered HTML didn't match the client properties." More detailed errors below.

Triage

This seems to happen because calling posthog.init loads a remote config JS file by inserting a script tag.

The error disappears if I disable remote script loading with disable_external_dependency_loading: true; however, that also disables surveys, so it's not ideal.

I can see two possible solutions:

  1. Expose a flag that would switch enable _loadRemoteConfigJSON by default. This should allow Nextjs to hydrate without error while still getting the settings.
  2. Let me, as the user of the library, optionally load config.js. E.g., if the library could skip inserting the script tag based on id, I could manually add <Script id="deterministic-posthog-config-key" strategy="beforeInteractive" src="https://my.app/ingest/array/phc_Ds…/config.js" /> in layout.tsx and therefore load the config without a warning.

Sample errors

Next 14.22

Given a <Script strategy="beforeInteractive" src="https://js.stripe.com/v3/" /> in the layout:

Prop `dangerouslySetInnerHTML` did not match. Server: "" Client: "(self.__next_s=self.__next_s||[]).push([\"https://js.stripe.com/v3/\",{}])"
script
Script
body
html
RootLayout (Server)
Component@
RedirectBoundary
Component@
NotFoundBoundary
DevRootNotFoundBoundary
PureComponent@
HotReload
Router
Component@
ErrorBoundary
AppRouter
ServerRoot
Root

Details

A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:

  • A server/client branch if (typeof window !== 'undefined').
  • Variable input such as Date.now() or Math.random() which changes each time it's called.
  • Date formatting in a user's locale which doesn't match the server.
  • External changing data without sending a snapshot of it along with the HTML.
  • Invalid HTML tag nesting.

It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.

https://react.dev/link/hydration-mismatch

...
<Router actionQueue={{state:{...}, ...}} assetPrefix="">



<ReactDevOverlay state={{nextId:1, ...}} dispatcher={{...}}>

<HTTPAccessFallbackBoundary notFound={}>
<HTTPAccessFallbackErrorBoundary pathname="/home" notFound={} ...>










<Script id="log-locati..." strategy="beforeInte...">
<script
nonce={undefined}
dangerouslySetInnerHTML={{

  •                           __html: "(self.__next_s=self.__next_s||[]).push([0,{\"children\":\"\\n            cons..."
    
  •                           __html: ""
                            }}
    
  •                         type="text/javascript"
    
  •                         crossorigin="anonymous"
    
  •                         src="https://my.app/ingest/array/phc_Ds..."
                          >
                        <Script strategy="beforeInte..." src="https://js.stripe.com...">
                          <script
                            nonce={undefined}
                            dangerouslySetInnerHTML={{
    
  •                           __html: "(self.__next_s=self.__next_s||[]).push([\"https://js.stripe.com/v3..."
    
  •                           __html: "(self.__next_s=self.__next_s||[]).push([0,{\"children\":\"\\n            cons..."
                            }}
                          >
    

</p>
</details> 
@freeatnet
Copy link
Author

This is possibly related to #774.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant