Describe the bug
This is not stricly a bug. But I believe its something that will effect many registries.
Registry auth fails on non-www/cross-host redirects since node-fetch was replaced with native fetch (4.11.1+)
Summary
The latest shadcn CLI 4.11.1+ switched from node-fetch to native fetch. Now shadcn add returns 401 Unauthorized for authenticated registries whose URL redirects across hosts (e.g. apex → www), even with a valid API key. Pointing the registry at the post-redirect (canonical) host works.
For example: Prior to this change our registry worked with both www and non-www urls https://www.shadcnblocks.com/r/{name} or https://shadcnblocks.com/r/{name}. After this change the non-www version no longer works.
{
"registries": {
"@shadcnblocks": {
"url": "https://www.shadcnblocks.com/r/{name}",
"headers": { "Authorization": "Bearer ${SHADCNBLOCKS_API_KEY}" }
}
}
}
Root cause
When a registry URL responds with a redirect to a different host (e.g. https://example.com/r/{name} → https://www.example.com/r/{name}), native fetch/undici drops the Authorization header on the cross-origin hop for security. The token never reaches the final host → 401.
node-fetch → native fetch
This changed behavior in 4.11.1 (commit 9197676, "chore: replace node-fetch", 2026-06-15), which removed node-fetch/https-proxy-agent in favor of native fetch + undici.
node-fetch used a lenient rule: it kept Authorization when the redirect target was the same domain or a subdomain (so apex → www preserved the header).
- Native
fetch/undici strips Authorization on any cross-origin redirect, including apex ↔ www.
| CLI version |
fetch impl |
cross-host redirect w/ auth |
| ≤ 4.11.0 |
node-fetch |
header preserved (same-domain/subdomain) |
| 4.11.1+ / current |
native fetch + undici |
header stripped → 401 |
Because npx shadcn (unpinned) resolves to the latest, configs that worked before now fail after a routine upgrade — with no change on the user's side.
Reproduction
- Configure an authenticated registry whose URL 301/308-redirects to another host (e.g. apex →
www):
{
"registries": {
"@shadcnblocks": {
"url": "https://shadcnblocks.com/r/{name}",
"headers": { "Authorization": "Bearer ${SHADCNBLOCKS_API_KEY}" }
}
}
}
- Both
npx shadcn@latest add @shadcnblocks/hero36 or npx shadcn@4.11.1 add @shadcnblocks/hero36 will fail with 401
- Change the URL to the redirect target host (
https://www.shadcnblocks.com/r/{name}) → succeeds.
Alternatively if you a cli version before 4.11.1 it will work with both www and non-ww versions
- make sure the url is non-www https://shadcnblocks.com/r/{name}
npx shadcn@4.11.0 add @shadcnblocks/hero36 will work
Verified behavior (same cross-host 308)
| Client |
Keeps Authorization? |
node-fetch (≤ 4.11.0) |
✅ kept on same-domain/subdomain |
native fetch / undici (4.11.1+) |
❌ stripped |
curl -L |
❌ stripped |
Impact
- Any registry that relies on a host-level redirect (apex →
www is extremely common on Vercel/Netlify/Cloudflare) breaks for authenticated installs on current CLI.
- Also affects
bunx, Deno, and CI, which strip cross-host auth regardless of version.
Immediate Mitigations
- Registry operators: publish the canonical (post-redirect) host in
components.json
- Avoid cross-host redirects on registry paths.
Possible fix
While this is likely expected native fetch behavior, the CLI could handle this case for a better ongoing DX.
Option 1: Document the caveat (lowest effort)
In registry/auth docs, note that:
- registry URLs should use the canonical URL (final URL after redirects)
- auth headers from
registries.*.headers are sent on the initial request only
- they are not re-sent across origin-changing redirects
Option 2: CLI warning (helpful, still spec-correct)
If a registry request fails with 401/403 and the response was reached via a redirect that changed host/scheme/port, emit a targeted message:
Auth headers were not sent to the redirected URL (www.example.com). Use the canonical registry URL in components.json.
Option 3: CLI compatibility layer (optional)
To restore prior node-fetch ergonomics for private registries:
- detect redirects where the target is the same registrable domain (e.g.
example.com ↔ www.example.com)
- manually follow the redirect and re-attach configured per-registry headers on the redirected request
This would be an intentional deviation from strict fetch redirect semantics, so it should probably be:
- opt-in (e.g.
followRegistryRedirects: true), or
- limited to same-site/subdomain cases only
Affected component/components
Registry
How to reproduce
- Configure an authenticated registry whose URL 301/308-redirects to another host (e.g. apex →
www):
{
"registries": {
"@shadcnblocks": {
"url": "https://shadcnblocks.com/r/{name}",
"headers": { "Authorization": "Bearer ${SHADCNBLOCKS_API_KEY}" }
}
}
}
- Both
npx shadcn@latest add @shadcnblocks/hero36 or npx shadcn@4.11.1 add @shadcnblocks/hero36 will fail with 401
- Change the URL to the redirect target host (
https://www.shadcnblocks.com/r/{name}) → succeeds.
Alternatively if you a cli version before 4.11.1 it will work with both www and non-ww versions
- make sure the url is non-www https://shadcnblocks.com/r/{name}
npx shadcn@4.11.0 add @shadcnblocks/hero36 will work
Codesandbox/StackBlitz link
No response
Logs
System Info
Before submitting
Describe the bug
This is not stricly a bug. But I believe its something that will effect many registries.
Registry auth fails on non-
www/cross-host redirects sincenode-fetchwas replaced with nativefetch(4.11.1+)Summary
The latest shadcn CLI 4.11.1+ switched from
node-fetchto nativefetch. Nowshadcn addreturns401 Unauthorizedfor authenticated registries whose URL redirects across hosts (e.g. apex →www), even with a valid API key. Pointing the registry at the post-redirect (canonical) host works.For example: Prior to this change our registry worked with both www and non-www urls https://www.shadcnblocks.com/r/{name} or https://shadcnblocks.com/r/{name}. After this change the non-www version no longer works.
Root cause
When a registry URL responds with a redirect to a different host (e.g.
https://example.com/r/{name}→https://www.example.com/r/{name}), nativefetch/undici drops theAuthorizationheader on the cross-origin hop for security. The token never reaches the final host →401.node-fetch→ nativefetchThis changed behavior in
4.11.1(commit9197676, "chore: replace node-fetch", 2026-06-15), which removednode-fetch/https-proxy-agentin favor of nativefetch+undici.node-fetchused a lenient rule: it keptAuthorizationwhen the redirect target was the same domain or a subdomain (so apex →wwwpreserved the header).fetch/undici stripsAuthorizationon any cross-origin redirect, including apex ↔www.Because
npx shadcn(unpinned) resolves to the latest, configs that worked before now fail after a routine upgrade — with no change on the user's side.Reproduction
www):{ "registries": { "@shadcnblocks": { "url": "https://shadcnblocks.com/r/{name}", "headers": { "Authorization": "Bearer ${SHADCNBLOCKS_API_KEY}" } } } }npx shadcn@latest add @shadcnblocks/hero36ornpx shadcn@4.11.1 add @shadcnblocks/hero36will fail with401https://www.shadcnblocks.com/r/{name}) → succeeds.Alternatively if you a cli version before 4.11.1 it will work with both www and non-ww versions
npx shadcn@4.11.0 add @shadcnblocks/hero36will workVerified behavior (same cross-host 308)
Authorization?node-fetch(≤ 4.11.0)fetch/ undici (4.11.1+)curl -LImpact
wwwis extremely common on Vercel/Netlify/Cloudflare) breaks for authenticated installs on current CLI.bunx, Deno, and CI, which strip cross-host auth regardless of version.Immediate Mitigations
components.jsonPossible fix
While this is likely expected native
fetchbehavior, the CLI could handle this case for a better ongoing DX.Option 1: Document the caveat (lowest effort)
In registry/auth docs, note that:
registries.*.headersare sent on the initial request onlyOption 2: CLI warning (helpful, still spec-correct)
If a registry request fails with 401/403 and the response was reached via a redirect that changed host/scheme/port, emit a targeted message:
Option 3: CLI compatibility layer (optional)
To restore prior
node-fetchergonomics for private registries:example.com↔www.example.com)This would be an intentional deviation from strict fetch redirect semantics, so it should probably be:
followRegistryRedirects: true), orAffected component/components
Registry
How to reproduce
www):{ "registries": { "@shadcnblocks": { "url": "https://shadcnblocks.com/r/{name}", "headers": { "Authorization": "Bearer ${SHADCNBLOCKS_API_KEY}" } } } }npx shadcn@latest add @shadcnblocks/hero36ornpx shadcn@4.11.1 add @shadcnblocks/hero36will fail with401https://www.shadcnblocks.com/r/{name}) → succeeds.Alternatively if you a cli version before 4.11.1 it will work with both www and non-ww versions
npx shadcn@4.11.0 add @shadcnblocks/hero36will workCodesandbox/StackBlitz link
No response
Logs
System Info
Before submitting