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
- 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>.
- Use the final (canonical) URL directly so no redirect following is needed.
- Fix the server-side redirect loop if you control it.
- 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
- Use canonical (final) registry URLs that do not redirect.
- Unset HTTP_PROXY/HTTPS_PROXY/ALL_PROXY if a proxy injects redirects.
- Curl -IL the URL to inspect the chain before wiring it into config.
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
- Failed to fetch registry item: ${response.statusText}
- Failed to fetch registries.
- Something went wrong fetching the registry icons.
- Failed to fetch components from registry.
- FETCH_ERROR
AI-assisted analysis of shadcn-ui/ui@efac598707 (2026-08-12).
Data as JSON: /api/errors/78b3ac30bfa70e3c.
Report an issue: GitHub.