shadcn-ui/ui · error · Error

Too many redirects while fetching ${url}

Error message

Too many redirects while fetching ${url}

What it means

Thrown by fetchWithProxy when following HTTP redirects exceeds MAX_REDIRECTS (5 hops). Redirects are followed manually so that cross-origin hops can strip sensitive caller headers. After 5+1 iterations of the loop without a non-redirect response, the loop exits and throws a plain Error (not a RegistryError - it has no code). This typically indicates a redirect loop or a server with an unusually long redirect chain.

Source

Thrown at packages/shadcn/src/registry/proxy.ts:131

    if (nextUrl.origin !== originalOrigin) {
      // Cross-origin hop: drop every caller-supplied header except the
      // non-sensitive Accept/User-Agent.
      const stripped = new Headers()
      originalHeaders.forEach((value, key) => {
        if (SAFE_HEADER_NAMES.has(key.toLowerCase())) {
          stripped.set(key, value)
        }
      })
      headers = stripped
    } else {
      headers = originalHeaders
    }

    currentUrl = nextUrl.toString()
  }

  throw new Error(`Too many redirects while fetching ${url}`)
}

async function fetchOnce(
  url: string,
  init: RequestInit | undefined,
  headers: Headers
) {
  try {
    // The `dispatcher` option is supported by Node's fetch at runtime but
    // missing from the ambient RequestInit type, hence the cast. Redirects are
    // followed manually (see fetchWithProxy) so headers can be re-scoped per
    // hop, hence `redirect: "manual"`.
    //
    // This must stay the global `fetch` binding: MSW's Node adapter patches
    // `globalThis.fetch`, so importing `fetch` from undici here would bypass
    // MSW's interceptor and break the registry tests.
    return await fetch(url, {
      ...init,

View on GitHub (pinned to efac598707)

Solutions

  1. Curl the URL with -IL to see the redirect chain and identify the loop or long chain: curl -sIL -o /dev/null -w '%{redirect_url}\n' <url>.
  2. Use the final (canonical) URL directly so no redirect following is needed.
  3. Fix the server-side redirect loop if you control it.
  4. If a proxy is injecting redirects, unset HTTP_PROXY/HTTPS_PROXY/ALL_PROXY and retry.

Example fix

// before - URL redirects through 6+ hops
await fetchWithProxy("https://example.com/registry/button.json")

// after - resolve the canonical URL via curl -IL, then use it
await fetchWithProxy("https://cdn.example.com/v2/button.json")
Defensive patterns

Strategy: try-catch

Validate before calling

async function assertShortRedirectChain(url: string, max = 5) {
  let current = url
  for (let i = 0; i <= max; i++) {
    const res = await fetch(current, { redirect: "manual" })
    if (res.status < 300 || res.status >= 400 || !res.headers.get("location")) return
    current = new URL(res.headers.get("location")!, current).toString()
  }
  throw new Error(`${url} exceeds ${max} redirects`)
}

Try / catch

try {
  await fetchWithProxy(url)
} catch (err) {
  if (err instanceof Error && /Too many redirects/.test(err.message)) {
    // resolve the canonical URL via curl -IL and pass that instead
  }
  throw err
}

Prevention

When it happens

Trigger: fetchWithProxy(url) where the server responds with 3xx + Location more than 5 times in a row. Each iteration requires status 300-399 and a 'location' header to count as a redirect. Common with redirect loops (A -> B -> A) or auth-gated CDNs that bounce through multiple login redirects.

Common situations: A misconfigured registry URL that redirects to itself or to a chain longer than 5. A private registry behind SSO that redirects through identity providers. HTTP -> HTTPS -> www -> auth cascades. A dying proxy inserting extra redirects.

Related errors


AI-assisted analysis of shadcn-ui/ui@efac598707 (2026-08-12). Data as JSON: /api/errors/78b3ac30bfa70e3c. Report an issue: GitHub.