nextjs - ✅(Solved) Fix createRedirectRenderResult fetch missing redirect: "manual" — causes errors and wasted latency on server action redirects [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#90136Fetched 2026-04-08 00:19:48
View on GitHub
Comments
1
Participants
2
Timeline
6
Reactions
0
Author
Timeline (top)
labeled ×2closed ×1commented ×1cross-referenced ×1

Error Message

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.

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 },
})

Fix Action

Fix / Workaround

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.

PR fix notes

PR #90137: fix: add redirect: "manual" to createRedirectRenderResult fetch

Description (problem / solution / changelog)

Summary

Fixes #90591

createRedirectRenderResult in action-handler.ts makes a fetch() call without redirect: 'manual', causing it to automatically follow the redirect chain of the target URL server-side. This leads to:

  • "redirect count exceeded" errors when the redirect target has a long chain (common with OAuth/SSO providers)
  • Wasted server-side latency even when the chain is short, because the server fetches the external page before handing the redirect back to the client

PR #65097 correctly added redirect: 'manual' to the sibling createForwardedActionResponse function but missed applying the same fix to createRedirectRenderResult.

This PR adds the missing redirect: 'manual' option to the fetch call in createRedirectRenderResult, making it consistent with createForwardedActionResponse.

How it was tested

Related

  • #65097 — the PR that added redirect: 'manual' to createForwardedActionResponse
  • #43704 — related issue about server-side fetching of redirect targets

Changed files

  • packages/next/src/server/app-render/action-handler.ts (modified, +1/-0)

Code Example

// 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 },
})

---

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
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/ajworkos/nextjs-redirect-bug-repro

To Reproduce

  1. Create a server action that calls redirect('/api/login') (or any internal route)
  2. The route handler at /api/login itself calls redirect('https://external-oauth-provider.com/authorize?...') — i.e., it redirects externally
  3. Wrap the server action in a client component <form action={...}> so it goes through the RSC action handler path
  4. 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.

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.

extent analysis

Fix: Add redirect: 'manual' to the fetch used in createRedirectRenderResult

The bug is caused by the internal fetch following redirects automatically.
Adding the redirect: 'manual' option makes Next.js forward the redirect to the client instead of chasing the chain.

Step‑by‑step implementation

  1. Locate the file
    packages/next/src/server/app-render/action-handler.ts (or the equivalent path in your repo).

  2. Edit the createRedirectRenderResult fetch call

    // BEFORE (current)
    const response = await fetch(fetchUrl, {
      method: 'GET',
      headers: forwardedHeaders,
      // ❌ missing redirect option
      next: { internal: 1 },
    });
    // AFTER (fixed)
    const response = await fetch(fetchUrl, {
      method: 'GET',
      headers: forwardedHeaders,
      redirect: 'manual',          // ← add this line
      next: { internal: 1 },
    });
  3. Run the test suite / type‑check

    pnpm install   # if you changed lockfile
    pnpm test      # ensure no regressions
    pnpm lint      # optional
  4. Re‑build and redeploy

    pnpm build     # next build
    pnpm start     # next start (dev) or push to Vercel
  5. Commit & PR

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

nextjs - ✅(Solved) Fix createRedirectRenderResult fetch missing redirect: "manual" — causes errors and wasted latency on server action redirects [1 pull requests, 1 comments, 2 participants]