mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[PR #464] [CLOSED] fix: return empty headers/cookies when called outside request context #590
Labels
No labels
enhancement
enhancement
good first issue
help wanted
nextjs-tracking
nextjs-tracking
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/vinext#590
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/cloudflare/vinext/pull/464
Author: @benfavre
Created: 3/11/2026
Status: ❌ Closed
Base:
main← Head:fix/headers-cookies-graceful-fallback📝 Commits (1)
5d85f6ffix: return empty headers/cookies when called outside request context📊 Changes
1 file changed (+11 additions, -11 deletions)
View changed files
📝
packages/vinext/src/shims/headers.ts(+11 -11)📄 Description
Problem
When
headers()orcookies()is called outside of a request's AsyncLocalStorage scope, the current code returns a rejected Promise. This crashes the process because:headers()insideReact.cache()wrappers at module initialization time — beforerunWithHeadersContext()sets up the ALS scopeStack trace
This happens during RSC module evaluation, not from a Client Component.
Solution
Return empty readonly
Headers/RequestCookiesobjects instead of rejecting whenstate.headersContextis null.This matches Next.js behavior — their
headers()andcookies()gracefully degrade when called outside request context. The real request headers become available when the component or procedure is actually invoked during rendering within the proper ALS scope.Changes
packages/vinext/src/shims/headers.tsheaders(): Return_sealHeaders(new Headers())wrapped in_decorateRequestApiPromiseinstead of_decorateRejectedRequestApiPromisecookies(): Return_sealCookies(new RequestCookies(new Map()))wrapped in_decorateRequestApiPromiseinstead of_decorateRejectedRequestApiPromiseBoth return readonly wrappers (sealed via Proxy) so mutation attempts still throw.
Reproduction
Risk
Low. The empty objects are readonly (mutations throw), and the fix only affects the edge case where there is no ALS store. Normal request-scoped calls are unaffected — the code path for
state.headersContext !== nullis unchanged.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.