shadcn-ui/ui · error · RegistryNotFoundError
NOT_FOUND
NOT_FOUND
Error message
The item at ${url} was not found. It may not exist at the registry. What it means
Thrown by getRegistryWithContext when buildUrlAndHeadersForRegistryItem returns a result whose url is missing. In practice the builder returns null for inputs it considers URL/local-file/local-path/GitHub-address forms; since the URL and GitHub branches are handled earlier in getRegistryWithContext, this fires when a local file path or local path string reaches the namespace-resolution path.
Source
Thrown at packages/shadcn/src/registry/api.ts:140
return fetchGitHubRegistryCatalog(githubSource, { useCache })
}
if (!name.startsWith("@")) {
throw new RegistryInvalidNamespaceError(name)
}
let registryName = name
if (!registryName.endsWith("/registry")) {
registryName = `${registryName}/registry`
}
const urlAndHeaders = buildUrlAndHeadersForRegistryItem(
registryName as `@${string}`,
configWithDefaults(config)
)
if (!urlAndHeaders?.url) {
throw new RegistryNotFoundError(registryName)
}
// Append search params before registering headers so the header lookup key
// matches the URL we actually fetch.
const url = appendSearchParamsToUrl(urlAndHeaders.url, searchParams)
if (urlAndHeaders.headers && Object.keys(urlAndHeaders.headers).length > 0) {
setRegistryHeaders({
[url]: urlAndHeaders.headers,
})
}
const [result] = await fetchRegistry([url], { useCache })
return parseRegistryCatalog(registryName, result)
}
function parseRegistryCatalog(name: string, result: unknown) {View on GitHub (pinned to efac598707)
Solutions
- If you want to load a local registry file, use loadRegistry({ registryFile: "..." }) from the loader module instead of getRegistry().
- If you want a remote registry, pass its full URL (http/https) or an '@namespace' name.
- If you want a GitHub source, use the owner/repo form.
- Strip leading './' or '/' if you intended a namespace name.
Example fix
// before
getRegistry("./registry.json")
// after
import { loadRegistry } from "@/src/registry/loader"
await loadRegistry({ registryFile: "./registry.json" }) Defensive patterns
Strategy: validation
Validate before calling
import { isUrl } from "@/src/registry/utils";
import { resolveGitHubRegistrySource } from "@/src/registry/address";
function chooseRegistryLoader(name: string) {
if (isUrl(name)) return "remote";
if (name.startsWith("./") || name.startsWith("/")) return "local-loader";
if (resolveGitHubRegistrySource(name)) return "github";
if (name.startsWith("@")) return "namespace";
throw new Error(`Cannot resolve registry reference: ${name}`);
}
// route './foo.json' to loadRegistry, not getRegistry Type guard
function isLocalRegistryRef(name: string): boolean {
return name.startsWith("./") || name.startsWith("/") || name.startsWith("~/");
} Try / catch
try {
await getRegistry(name);
} catch (err) {
if (err instanceof RegistryNotFoundError && isLocalRegistryRef(name)) {
// fall back to the local loader
return loadRegistry({ registryFile: name });
}
throw err;
} Prevention
- Use loadRegistry() for local files; reserve getRegistry() for URLs, namespaces, GitHub sources.
- Add an input router at the call site so paths never reach the namespace branch.
- Unit-test the routing decision before invoking the network path.
When it happens
Trigger: Calling getRegistry() with a string that starts with './' or '/' (a local path) or is otherwise treated as local, so buildUrlAndHeadersForRegistryItem short-circuits to null and urlAndHeaders?.url is undefined.
Common situations: Passing a relative or absolute filesystem path to getRegistry (which expects a registry namespace, URL, or GitHub source). Mixing up the local loader (loadRegistry) with the remote registry catalog fetcher.
Related errors
AI-assisted analysis of shadcn-ui/ui@efac598707 (2026-08-12).
Data as JSON: /api/errors/6ba383e9248b824b.
Report an issue: GitHub.