Skip to content

Commit 7dfbe69

Browse files
committed
fix(landing): handle runtime env race on error-page renders
React skips SSR on unhandled server errors and re-renders on the client (see vercel/next.js#63980, #82456). Root-layout scripts — including the runtime env script that populates window.__ENV — are inserted but not executed on that client re-render, so any client module that reads env at module evaluation crashes the render into a blank "Application error" overlay instead of rendering the styled 404. This replaces the earlier PublicEnvScript tweak with the architectural fix: - auth-client.ts: fall back to window.location.origin when getBaseUrl() throws on the client. Auth endpoints are same-origin, so this is the correct baseURL on the client. Server-side we still throw on genuine misconfig. - loading.tsx under /models/[provider], /models/[provider]/[model], and /integrations/[slug]: establishes a Suspense boundary below the root layout so a page-level notFound() no longer invalidates the layout's SSR output (the fix endorsed by Next.js maintainers in #63980). - layout.tsx: revert disableNextScript — the research showed this doesn't actually fix error-page renders. The real fix is above.
1 parent 0d439cf commit 7dfbe69

5 files changed

Lines changed: 29 additions & 2 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function IntegrationDetailLoading() {
2+
return <div className='min-h-[60vh]' aria-hidden />
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function ModelDetailLoading() {
2+
return <div className='min-h-[60vh]' aria-hidden />
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function ModelProviderLoading() {
2+
return <div className='min-h-[60vh]' aria-hidden />
3+
}

apps/sim/app/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
239239
</>
240240
)}
241241

242-
<PublicEnvScript disableNextScript />
242+
<PublicEnvScript />
243243
</head>
244244
<body className={`${season.variable} font-season`} suppressHydrationWarning>
245245
{/* Google Tag Manager (noscript) — hosted only */}

apps/sim/lib/auth/auth-client.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,26 @@ import { isBillingEnabled, isOrganizationsEnabled } from '@/lib/core/config/feat
1515
import { getBaseUrl } from '@/lib/core/utils/urls'
1616
import { SessionContext, type SessionHookResult } from '@/app/_shell/providers/session-provider'
1717

18+
/**
19+
* On Next.js error-page renders (`<html id="__next_error__">`), scripts from the
20+
* root layout — including the runtime env script that populates `window.__ENV`
21+
* — are inserted but not executed by React (see vercel/next.js#63980, #82456).
22+
* Calling `getBaseUrl()` here at module evaluation would then throw and cascade
23+
* the error-page render into a blank "Application error" overlay. On the
24+
* client, auth endpoints are same-origin, so `window.location.origin` is a
25+
* correct fallback; server-side we still surface a genuine misconfig.
26+
*/
27+
function getAuthBaseUrl(): string {
28+
try {
29+
return getBaseUrl()
30+
} catch (e) {
31+
if (typeof window !== 'undefined') return window.location.origin
32+
throw e
33+
}
34+
}
35+
1836
export const client = createAuthClient({
19-
baseURL: getBaseUrl(),
37+
baseURL: getAuthBaseUrl(),
2038
plugins: [
2139
adminClient(),
2240
emailOTPClient(),

0 commit comments

Comments
 (0)