Skip to content

Inline script from layout doesn't run on not found page when using parallel routes #82456

@dmitrc

Description

@dmitrc

Link to the code that reproduces this issue

https://github.com/dmitrc/nextjs-packagelocalizationprovider-repro

To Reproduce

  1. Start the dev server (next start behaves the same way)
  2. Navigate to /test and press "Check" button
  3. Observe that a global value set from LocalizedStringProvider's script has been set
Image
  1. Now navigate to /zzz (that will 404) and press "Check" button
  2. Observe that a global value set from LocalizedStringProvider's script has NOT been set
Image
  1. Search for window[Symbol.for('react-aria.i18n.locale')] in the DOM to find the relevant script (meaning it was rendered, but not executed)
Image
  1. Now remove the parallel route by deleting @modal folder and corresponding layout slot
  2. Restart the dev server
  3. Repeat the test above, and observe that it works as expected now
Image

Current vs. Expected behavior

This issue is weird, but I was able to isolate it to the minimal repro linked above.

Concepts

React-Aria's LocalizedStringProvider is a server-side component that writes a <script> which puts some strings in a global variable on window. This is normally included in the server-side layout output, and allows to optimize the client JS bundle by only pre-baking the strings for the specific locale that the user needs.

not-found.tsx file in the root allows to show custom UI when notFound() was invoked or none of the routes have matched. This clearly follows some different rendering path, as it starts with an almost-blank page, and then streams stuff in, including the root layout.

Parallel routes allow to render two slots of UI at once, based on the concurrent routing to the main app model and @slot. In our app, we render a dynamic route for all pages, allowing us to embed a modal or a custom view on all "normal" pages. I am not sure how this plays out in the whole picture here, but when you remove this, everything works as expected.

Issue

When loading the normal routes directly, the script is rendering and executed as intended, so React-Aria components are able to get the locale and corresponding strings. "Check" button of this demo does a crude check directly from window to showcase the results.

However, when going through a not found route (same thing happens on error handlers too), the rendering takes a different path. The page starts blank. the layout is streamed in, the <script> tag is present in the DOM, but it never executes somehow. The "Check" button reveals that the global value is undefined. If you were to embed a <Popover> or other React-Aria component requiring these strings on that page, it would throw (which is what brings me here today).

Observations

At first, I thought it was a generic defect of streamed layouts in the context of not found / error handlers, but this issue does not occur when removing the usage of the parallel routes.

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP Tue Nov 5 00:21:55 UTC 2024
  Available memory (MB): 32022
  Available CPU cores: 32
Binaries:
  Node: 22.16.0
  npm: 10.9.2
  Yarn: N/A
  pnpm: 9.15.4
Relevant Packages:
  next: 15.4.6 // Latest available version is detected (15.4.6).
  eslint-config-next: N/A
  react: 19.1.0
  react-dom: 19.1.0
  typescript: 5.9.2
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Parallel & Intercepting Routes, Not Found, Error Handling

Which stage(s) are affected? (Select all that apply)

next dev (local), next start (local)

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Error HandlingRelated to handling errors (e.g., error.tsx, global-error.tsx).Not FoundRelated to the not-found.tsx file or the notFound() function.Parallel & Intercepting RoutesRelated to Parallel and/or Intercepting routes.

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions