shadcn-ui/ui · error · RegistryGoneError

GONE

GONE

Error message

The item at ${url} is no longer available. It may have been removed or expired.

What it means

Thrown by fetchRegistry when the registry endpoint responds with HTTP 410 Gone. RegistryGoneError indicates the resource was deliberately removed and the endpoint is signalling permanence, distinguishing it from a transient 404.

Source

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

                // Prefer RFC 7807 detail field, then message field.
                messageFromServer = parsed.data.detail || parsed.data.message

                if (parsed.data.error) {
                  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)

View on GitHub (pinned to efac598707)

Solutions

  1. Migrate to the replacement item/version indicated by the registry's changelog.
  2. Pin to a registry version/tag that still serves the item.
  3. Contact the registry maintainer if no replacement is documented.
  4. If you control the registry, ensure a documented migration path exists before returning 410.

Example fix

// before
npx shadcn add @myorg/button@v1  // returns 410

// after
npx shadcn add @myorg/button@v2
Defensive patterns

Strategy: try-catch

Validate before calling

// 410 is terminal; validate availability from a catalog listing before fetch.
async function assertItemNotGone(registryUrl: string, itemName: string) {
  const [catalog] = await fetchRegistry([registryUrl]);
  const exists = catalog.items?.some((i: { name: string }) => i.name === itemName);
  if (!exists) throw new Error(`${itemName} is not in the catalog (possibly gone).`);
}

Type guard

function isGoneError(err: unknown): boolean {
  return err instanceof RegistryGoneError;
}

Try / catch

try {
  await fetchRegistry([url]);
} catch (err) {
  if (err instanceof RegistryGoneError) {
    // do NOT retry; surface migration guidance from the registry changelog
  }
  throw err;
}

Prevention

When it happens

Trigger: An item or catalog endpoint that was deprecated and explicitly returns 410, or a registry that prunes old versions and marks removed items as gone rather than missing.

Common situations: Upstream registry versioning policy removes an old major version of an item and serves 410 to force migration. A registry sunsets a namespace and signals it via 410.

Related errors


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