shadcn-ui/ui · error · RegistryForbiddenError

FORBIDDEN

FORBIDDEN

Error message

You are not authorized to access the item at ${url}. If this is a remote registry, you may need to authenticate.

What it means

Thrown by fetchRegistry when the registry endpoint responds with HTTP 403. RegistryForbiddenError means the request was authenticated (or auth was not required) but the principal is not permitted to access this specific resource. Distinct from 401 (no/invalid auth).

Source

Thrown at packages/shadcn/src/registry/fetcher.ts:103

                  messageFromServer = `[${parsed.data.error}] ${messageFromServer}`
                }
              }
            }

            if (response.status === 401) {
              throw new RegistryUnauthorizedError(url, messageFromServer)
            }

            if (response.status === 404) {
              throw new RegistryNotFoundError(url, messageFromServer)
            }

            if (response.status === 410) {
              throw new RegistryGoneError(url, messageFromServer)
            }

            if (response.status === 403) {
              throw new RegistryForbiddenError(url, messageFromServer)
            }

            throw new RegistryFetchError(
              url,
              response.status,
              messageFromServer
            )
          }

          return response.json()
        })()

        if (options.useCache) {
          registryCache.set(cacheKey, fetchPromise)
        }
        return fetchPromise
      })
    )

View on GitHub (pinned to efac598707)

Solutions

  1. Confirm the token has the required scope/entitlement for the item.
  2. Check whether the registry enforces IP/origin allow-lists and request access.
  3. Add any required custom headers (e.g. entitlement, plan) in components.json headers.
  4. Contact the registry operator to grant access if the token should work.

Example fix

// before: token lacks scope
{ "headers": { "Authorization": "Bearer ${REGISTRY_TOKEN}" } }

// after: use a token with the required scope / add entitlement header
{ "headers": {
    "Authorization": "Bearer ${REGISTRY_TOKEN}",
    "X-Plan": "${REGISTRY_PLAN}"
} }
Defensive patterns

Strategy: validation

Validate before calling

function ensureEntitlementHeaders(config: { headers?: Record<string,string> }, required: string[]) {
  const present = new Set(Object.keys(config.headers ?? {}).map(k => k.toLowerCase()));
  const missing = required.filter(h => !present.has(h.toLowerCase()));
  if (missing.length) throw new Error(`Missing headers: ${missing.join(", ")}`);
}

Type guard

function isForbiddenError(err: unknown): boolean {
  return err instanceof RegistryForbiddenError;
}

Try / catch

try {
  await fetchRegistry([url]);
} catch (err) {
  if (err instanceof RegistryForbiddenError) {
    // prompt for an upgraded token / entitlement, then retry once
  }
  throw err;
}

Prevention

When it happens

Trigger: A valid token that lacks scope for the requested item, an IP/origin restriction on the registry, or a registry that allows listing but restricts certain items to paid/entitled users.

Common situations: Team-tier item on a paid registry accessed with a free-tier token, geo/IP blocking by a corporate registry, or a registry that requires an additional entitlement header.

Understand the failure class

Related errors


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