createRedirectRenderResult fetch missing redirect: "manual" — causes errors and wasted latency on server action redirects
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 142k
- Forks
- 32.5k
- Avg merge
- 2d 14h
- Merged PRs (30d)
- 351
Description
Link to the code that reproduces this issue
https://github.com/ajworkos/nextjs-redirect-bug-repro
To Reproduce
- Create a server action that calls
redirect('/api/login')(or any internal route) - The route handler at
/api/loginitself callsredirect('https://external-oauth-provider.com/authorize?...')— i.e., it redirects externally - Wrap the server action in a client component
<form action={...}>so it goes through the RSC action handler path - Submit the form
Expected: The client receives the redirect and navigates to the external URL.
Actual (Demo 1 — error): If the external URL has a redirect chain (common with OAuth/SSO providers), the server-side fetch in createRedirectRenderResult follows all redirects and hits the "redirect count exceeded" limit, causing a 500 error.
Actual (Demo 2 — latency): Even when the chain is short enough to not error, the server unnecessarily fetches the external redirect target (e.g., a slow OAuth authorization page), adding seconds of wasted latency before the client gets the redirect response.
Current vs Expected behavior
Current: createRedirectRenderResult in packages/next/src/server/app-render/action-handler.ts makes a fetch() call without redirect: 'manual', causing it to automatically follow the entire redirect chain of the target URL server-side.
Expected: The fetch should use redirect: 'manual' (just like the sibling function createForwardedActionResponse already does), so the redirect is handed back to the client via the x-action-redirect header without following it server-side.
Root Cause
PR #65097 correctly added redirect: 'manual' to the createForwardedActionResponse function but missed applying the same fix to createRedirectRenderResult. The two functions serve similar roles (forwarding action responses), and the inconsistency means createRedirectRenderResult still follows redirects automatically.
The relevant code is at:
// createForwardedActionResponse — has the fix ✅
const response = await fetch(fetchUrl, {
method: 'POST',
body,
duplex: 'half',
headers: forwardedHeaders,
redirect: 'manual', // ← present
next: { internal: 1 },
})
// createRedirectRenderResult — missing the fix ❌
const response = await fetch(fetchUrl, {
method: 'GET',
headers: forwardedHeaders,
// ← redirect: 'manual' missing
next: { internal: 1 },
})
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 23.6.0
Binaries:
Node: 20.17.0
npm: 10.8.2
pnpm: 9.15.0
Runtime Versions:
next: 16.1.6
Which area(s) are affected? (Select all that apply)
Server Actions
Which stage(s) are affected? (Select all that apply)
next dev, next build (production), Deployed (Vercel or other)
Additional context
This is a one-line fix: add redirect: 'manual' to the fetch call in createRedirectRenderResult, matching what #65097 already did for createForwardedActionResponse.
I have a PR ready with the fix: #90137
The real-world impact is significant for any app where server actions redirect to route handlers that perform OAuth/SSO redirects (a very common pattern). We discovered this while upgrading a production auth application from Next.js 14 to 16. In v14, we had been carrying a workaround using relative URLs to avoid this codepath, but the underlying bug has existed since createRedirectRenderResult was introduced.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in packages/next/src/server/app-render/action-handler.ts and compare createRedirectRenderResult with createForwardedActionResponse, which already uses manual redirects. Reproduce the redirect chain with the linked nextjs-redirect-bug-repro project, then verify that the external redirect is returned to the client without server-side follow-up or added latency.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, next.js
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 1/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100