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

Server action throws when accessing headers if invoked before hydration #73992

Closed
jonathanhefner opened this issue Dec 16, 2024 · 6 comments · Fixed by #74196
Closed

Server action throws when accessing headers if invoked before hydration #73992

jonathanhefner opened this issue Dec 16, 2024 · 6 comments · Fixed by #74196
Labels
bug Issue was opened via the bug report template. linear: next Confirmed issue that is tracked by the Next.js team.

Comments

@jonathanhefner
Copy link
Contributor

jonathanhefner commented Dec 16, 2024

Link to the code that reproduces this issue

https://codesandbox.io/p/devbox/nice-rgb-xsqkxt

To Reproduce

  1. Start the application in development.
  2. Open the preview in a dedicated browser tab.
  3. Disable JavaScript in that tab using the browser's dev console (Chrome instructions; in Firefox, click the cog wheel menu in the upper right corner of the debugger).
  4. Refresh the tab.
  5. On the application root page, click the "Action without headers" button. Notice that the action works and the browser is successfully redirected.
  6. Navigate back.
  7. On the application root page, click the "Action with headers" button. The action does not work. The following error appears in the server log:
     ⨯ Error: `headers` was called outside a request scope. Read more: https://nextjs.org/docs/messages/next-dynamic-api-wrong-context
        at headers (app/actions.ts:11:16)
       9 |
      10 | export async function actionWithHeaders() {
    > 11 |   (await headers()).get("referer");
         |                ^
      12 |   redirect(`/result/${Date.now()}`);
      13 | }
    

Current vs. Expected behavior

I expect the actionWithHeaders() action to succeed just like the actionWithoutHeaders() action. If for some reason that isn't possible, I expect a more accurate error message (headers is, in fact, being called inside a request scope).

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP PREEMPT_DYNAMIC Sun Aug  6 20:05:33 UTC 2023
  Available memory (MB): 4102
  Available CPU cores: 2
Binaries:
  Node: 20.9.0
  npm: 9.8.1
  Yarn: 1.22.19
  pnpm: 8.10.2
Relevant Packages:
  next: 15.1.1-canary.6 // Latest available version is detected (15.1.1-canary.6).
  eslint-config-next: N/A
  react: 19.0.0
  react-dom: 19.0.0
  typescript: 5.3.3
Next.js Config:
  output: N/A

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

Not sure

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

next dev (local)

Additional context

No response

@jonathanhefner jonathanhefner added the bug Issue was opened via the bug report template. label Dec 16, 2024
@OlegLustenko
Copy link

OlegLustenko commented Dec 17, 2024

We have similiar issue, but it happens for pages with prefetch.
headers and cookies are in fact called in server actions, but we are getting the same issue and only in production builds only with Next 15

 ⨯ Error: `headers` was called outside a request scope. Read more: https://nextjs.org/docs/messages/next-dynamic-api-wrong-context
    at headers (app/actions.ts:11:16)

I have a hard times trying to build an easy example for it. However it seems like ALS loosing context between prefetching

@AdamMikacich
Copy link

Having the same issue (also occurs with cookies as they're assigning a Set-Cookie header). Here is a simple example that you can test in a fresh Next.js install.

import { cookies } from "next/headers";

export async function setCookieAction() {
  "use server";

  // Works with JavaScript enabled (and loaded)
  // Otherwise: Error: `cookies` was called outside a request scope.
  const cookieStore = await cookies();
  cookieStore.set("myCookie", "myValue");
}

export default function Page() {
  return (
    <form action={setCookieAction}>
      <button type="submit">Set Cookie</button>
    </form>
  );
}

@unstubbable unstubbable added the linear: next Confirmed issue that is tracked by the Next.js team. label Dec 20, 2024
unstubbable added a commit that referenced this issue Dec 20, 2024
When scoping the `requestStore` to dynamic renders in #72312, we missed
the case when a server action is invoked before hydration is complete.

This leads to an error when a server action tries to read headers,
cookies, or anything else that requires the presence of the
`requestStore`.

This fixes that for both the Node.js and Edge runtimes. It also appears
that progressively enhanced form actions did not work at all before in
the Edge runtime due to a missing `await` of `decodeFormState`.

fixes #73992
unstubbable added a commit that referenced this issue Dec 20, 2024
When scoping the `requestStore` to dynamic renders in #72312, we missed
the case when a server action is invoked before hydration is complete.

This leads to an error when a server action tries to read headers,
cookies, or anything else that requires the presence of the
`requestStore`.

This fixes that for both the Node.js and Edge runtimes. It also appears
that progressively enhanced form actions did not work at all before in
the Edge runtime due to a missing `await` of `decodeFormState`.

fixes #73992
closes NAR-55
@OlegLustenko
Copy link

Hey @unstubbable ! Thanks for attention for this issue!

It still reproduces in our case, not all the time but all the time for full prefetching requests

@unstubbable
Copy link
Contributor

@OlegLustenko I don't understand how prefetching is related to this progressive enhancement issue with server actions. Can you elaborate?

@OlegLustenko
Copy link

@unstubbable sure! Sorry for not following a proper issue format with reproducing code-base
I had hard time reproducing this issue in a fresh code-base.

I recorded a short video explaining some cases, in our case it's pretty flaky bug that appearing on some pages but all the time with prefetching

prefetching.bug.mp4

If I can provide more information I'll be glad to! It also fine if we should open a new issue for this

@unstubbable
Copy link
Contributor

Yeah, so this doesn't seem to be related to server actions that are sent before hydration at all. Can you please try to reduce your case to a minimal reproduction and create a new issue with it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue was opened via the bug report template. linear: next Confirmed issue that is tracked by the Next.js team.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants