shadcn-ui/ui · error · RegistryValidationError

VALIDATION_ERROR

VALIDATION_ERROR

Error message

Invalid source registry file at ${registryFile}: registries that use include must be named registry.json.

What it means

Thrown by readSourceRegistryWithIncludes when the root registry declares an `include` array (so the include mechanism is in use) but the file's basename is not `registry.json`. shadcn enforces that any registry using includes must itself be named registry.json, so that included files can be addressed uniformly and the included-from metadata stays consistent. Fires only on the root file passed via options.registryFile.

Source

Thrown at packages/shadcn/src/registry/source.ts:118

        registryFile,
        registryDir,
        itemIndex,
      }
      context.itemSources.set(item.name, source)
      context.itemSourcesByItem.set(item, source)
    })
    validateDuplicateItems(rootRegistry.items, context.itemSourcesByItem)

    return {
      registry: rootRegistry,
      itemSources: context.itemSources,
      itemSourcesByItem: context.itemSourcesByItem,
      usesInclude,
    }
  }

  if (path.posix.basename(registryFile) !== "registry.json") {
    throw new RegistryValidationError(
      `Invalid source registry file at ${registryFile}: registries that use include must be named registry.json.`,
      { registryFile }
    )
  }

  const result = await readRegistryFile(
    registryFile,
    rootRegistry,
    reader,
    context,
    []
  )

  validateDuplicateItems(result.items, context.itemSourcesByItem)

  const { include, ...registry } = result
  validateRootRegistry(registry, registryFile)

View on GitHub (pinned to efac598707)

Solutions

  1. Rename the root file to `registry.json` (the convention shadcn enforces).
  2. If you must keep a custom name, remove the `include` field from that file and inline the items directly.

Example fix

// before — file named my-registry.json with include
// my-registry.json
{ "include": ["./ui/registry.json"], "items": [] }

// after — rename file to registry.json and keep include
// registry.json
{ "include": ["./ui/registry.json"], "items": [] }
Defensive patterns

Strategy: validation

Validate before calling

import path from "path";

function registryFileUsableWithIncludes(registryFile: string, root: { include?: string[] }) {
  if (!root.include?.length) return { ok: true };
  return path.posix.basename(registryFile) === "registry.json"
    ? { ok: true }
    : { ok: false, reason: "include-requires-registry-json-name" };
}

Type guard

function isCanonicalRegistryFileName(registryFile: string): boolean {
  return path.posix.basename(registryFile) === "registry.json";
}

Try / catch

import { RegistryValidationError } from "@/src/registry/errors";

try {
  await loadRegistryItemFromSource(name, reader, { registryFile: "my-registry.json" });
} catch (e) {
  if (e instanceof RegistryValidationError && /must be named registry.json/.test(e.message)) {
    // rename file to registry.json and retry
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `loadRegistryItemFromSource(name, reader, { registryFile: 'my-registry.json' })` where my-registry.json has a non-empty `include` array.

Common situations: A custom build pipeline passes a non-default registryFile name; a team renamed their root registry for namespacing reasons but still wants to compose via includes.

Related errors


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