Skip to content

fix: resolve /pricing hydration mismatch for OAuth redirects and non-en-US locales #SUPERLOG - #417

Open
superlog-app[bot] wants to merge 1 commit into
mainfrom
superlog/pricing-hydration-fix
Open

fix: resolve /pricing hydration mismatch for OAuth redirects and non-en-US locales #SUPERLOG#417
superlog-app[bot] wants to merge 1 commit into
mainfrom
superlog/pricing-hydration-fix

Conversation

@superlog-app

@superlog-app superlog-app Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Users arriving at /pricing via an OAuth redirect (URL hash contains #sso-callback or #verify) or with a non-en-US browser locale see React error #418 — the pricing page hydrates with a tree that doesn't match the pre-rendered server HTML, so React regenerates the whole tree on the client and emits the error.

Root cause

The /pricing route is pre-rendered at build time using renderToString and served as static HTML. When the browser loads the page, main.tsx calls hydrateRoot because the root element already contains pre-rendered content.

The Pricing component had a useState lazy initializer that branched on typeof window === "undefined" — the classic SSR/client mismatch pattern React's own docs flag as a cause of error #418:

  • Server-side (SSR): window is undefined → returns null → no <AuthModal> in the rendered tree.
  • Client hydration: window is defined → reads window.location.hash → returns "sign-in" if the hash includes sso-callback or verify (OAuth redirect landing) → <AuthModal> is included → structural divergence.

Additionally, three ScaleSlider instances used n.toLocaleString() (no locale argument) for the spans/logs/metrics value readout. The Node.js prerender environment formats numbers using its default locale (en-US), but a browser with a different locale (e.g., German) produces different digit separators ("2.000.000" vs "2,000,000"), causing a text-node mismatch for every non-en-US visitor.

Remediation

useState initializer: replaced with useState<AuthMode>(null) (always null, matching SSR) and a useEffect that reads the hash after hydration and calls setAuthMode("sign-in") when needed. The modal still opens for OAuth redirect users — just after the first paint rather than on the initial render, which is imperceptible.

toLocaleString(): pinned to "en-US" so the prerender and every browser produce identical strings regardless of system locale.


Incident: moonlit-tapir


Was this PR helpful? Leave feedback — goes straight to the Superlog team.


Summary by cubic

Fixes hydration mismatch on /pricing for OAuth redirect landings and non‑en-US locales, eliminating React hydration errors and flicker.

  • Bug Fixes
    • Initialize authMode to null and set it in a useEffect after hydration based on window.location.hash (#sso-callback, #verify) to avoid SSR/client divergence.
    • Pin number formatting to n.toLocaleString("en-US") in estimators so prerendered HTML matches all browsers.

Written for commit c3dc703. Summary will update on new commits.

Review in cubic

…en-US locales #SUPERLOG

Delivery-Id: 1512dd000c228aedef6cade43c6f46516f719d81621751c6660fefbc6fcadf92
Delivery-Base: main

@superlog-app superlog-app Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Observability review

All clear — no observability concerns found.

This PR understood the assignment.

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

Successfully merging this pull request may close these issues.

1 participant