shadcn-ui/ui · error · RegistrySourceFileError

Failed to resolve GitHub ref "${ref}" for ${address.owner}/$

Error message

Failed to resolve GitHub ref "${ref}" for ${address.owner}/${address.repo}. ${guidance.detail}

What it means

This error means ref resolution reached an authenticated GitHub transport (gh CLI or REST API with a token) but the request failed for a transport-level reason other than 404, missing gh, or missing credentials — e.g. HTTP 401/403/429/5xx, timeouts, or network failures. The message includes the ref, the owner/repo, and a guidance detail produced by getGitHubTransportFailureGuidance (rate-limit, permission, or network advice). It wraps the failure in a RegistrySourceFileError with reason 'github-ref-resolution'.

Source

Thrown at packages/shadcn/src/registry/github-ref.ts:193

      throw refError
    }

    const guidance = getGitHubTransportFailureGuidance(error, mode)

    // A missing gh binary or missing credentials keeps the original message
    // and adds setup guidance.
    if (error.kind === "enoent" || error.kind === "unauthenticated") {
      throw new RegistrySourceFileError("registry.json", undefined, {
        message: refError.message,
        context: {
          reason: "github-ref-resolution",
          source: formatGitHubSource(address),
          ref,
        },
        suggestion: guidance.suggestion,
      })
    }
    throw new RegistrySourceFileError("registry.json", undefined, {
      message: `Failed to resolve GitHub ref "${ref}" for ${address.owner}/${address.repo}. ${guidance.detail}`,
      context: {
        reason: "github-ref-resolution",
        source: formatGitHubSource(address),
        ref,
      },
      suggestion: guidance.suggestion,
    })
  }
}

function createGitHubRefResolutionError(
  address: GitHubSource,
  ref: string,
  repoUrl: string,
  error: unknown
) {
  return new RegistrySourceFileError("registry.json", error, {

View on GitHub (pinned to 683a5a9b37)

Solutions

  1. Check guidance.detail and the error context: for 429 rate limits, wait or add a token (gh auth login / GH_TOKEN) to raise the limit
  2. Run `gh auth status` to confirm the token is valid, not expired, and authorized for the org (SSO) if the repo is private
  3. Retry after a short backoff — transient 5xx and network blips usually resolve; check https://www.githubstatus.com during incidents
  4. Verify the network path to api.github.com (proxy, HTTPS_PROXY, DNS, firewall) from the environment running the CLI
  5. Confirm the ref actually exists on the remote (`git ls-remote https://github.com/owner/repo`) to rule out ref problems surfacing as transport errors

Example fix

# before
GH_TOKEN=expired-token npx shadcn add owner/repo
# -> Failed to resolve GitHub ref "main" for owner/repo. ... 401 ...

# after
export GH_TOKEN=$(gh auth token)  # fresh valid token
npx shadcn add owner/repo
Defensive patterns

Strategy: retry

Validate before calling

async function githubReachable(): Promise<boolean> {
  try {
    const res = await fetch("https://api.github.com/rate_limit", {
      headers: process.env.GH_TOKEN ? { Authorization: `Bearer ${process.env.GH_TOKEN}` } : {},
    })
    return res.ok || res.status === 403 || res.status === 429 // still reachable
  } catch { return false }
}
// before resolving many refs, verify reachability and token validity

Type guard

function isRegistrySourceFileError(e: unknown): e is RegistrySourceFileError {
  return e instanceof RegistrySourceFileError
}
function isGitHubRefResolutionFailure(e: unknown): boolean {
  return (
    isRegistrySourceFileError(e) &&
    (e.context as any)?.reason === "github-ref-resolution"
  )
}

Try / catch

async function withRetry<T>(fn: () => Promise<T>, attempts = 3): Promise<T> {
  for (let i = 0; i < attempts; i++) {
    try {
      return await fn()
    } catch (error) {
      if (isGitHubRefResolutionFailure(error) && /rate limit|5xx|timeout|ETIMEDOUT/i.test(error.message)) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000))
        continue
      }
      throw error
    }
  }
  throw new Error("GitHub ref resolution failed after retries")
}

Prevention

When it happens

Trigger: Calling a registry add/fetch that resolves a GitHub ref where the authenticated transport throws a GitHubTransportError whose kind is not 'enoent' or 'unauthenticated' and not an HTTP 404: rate limiting (HTTP 429), bad/expired token (401), SAML/organization blocking (403), GitHub 5xx outages, proxy/DNS/network failures, or timeouts while running `gh` or hitting the GitHub API for owner/repo at the given ref.

Common situations: Unauthenticated or low-rate-limit requests hitting GitHub API rate limits in CI; expired PAT used as GH_TOKEN; private repos in orgs requiring SSO authorization; corporate proxies or firewalls blocking api.github.com; GitHub incidents; too many parallel ref resolutions in monorepo builds.

Related errors


AI-assisted analysis of shadcn-ui/ui@683a5a9b37 (2026-08-27). Data as JSON: /api/errors/cec03811517a130b. Report an issue: GitHub.