shadcn-ui/ui · error · RegistryValidationError

VALIDATION_ERROR

VALIDATION_ERROR

Error message

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

What it means

Thrown by readRegistryWithIncludes when a registry file declares an 'include' array but is not itself named registry.json. shadcn enforces a naming convention: only a file literally named registry.json may act as the root of an include tree, because the include resolution logic and downstream path rewriting anchor on that basename. Without it, included chunks cannot be reliably resolved relative to a stable root.

Source

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

      const source = {
        registryFile: rootFile,
        registryDir: context.cwd,
        itemIndex,
      }
      context.itemSources.set(item.name, source)
      context.itemSourcesByItem.set(item, source)
    })

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

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

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

  validateDuplicateItems(result.items, context.itemSourcesByItem)

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

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

View on GitHub (pinned to efac598707)

Solutions

  1. Rename the root registry file to registry.json (the literal basename must be 'registry.json').
  2. If you cannot rename the file, remove the 'include' field from it and instead point loadRegistry directly at the appropriate registry.json.
  3. Pass an explicit registryFile option that resolves to a path whose basename is registry.json.

Example fix

// before
// file: ./app-registry.json  with  { "include": ["./ui/registry.json"] }
await loadRegistry({ registryFile: "app-registry.json" })

// after
// rename file to ./registry.json
await loadRegistry({ registryFile: "registry.json" })
Defensive patterns

Strategy: validation

Validate before calling

import * as path from "path"

function assertRootRegistryName(registryFile: string, hasIncludes: boolean) {
  if (hasIncludes && path.basename(registryFile) !== "registry.json") {
    throw new Error(
      `Root registry '${registryFile}' uses includes but is not named registry.json.`
    )
  }
}

// before calling loadRegistry:
const raw = JSON.parse(await fs.readFile(registryFile, "utf-8"))
assertRootRegistryName(registryFile, Array.isArray(raw.include) && raw.include.length > 0)

Type guard

function isRootRegistryCandidate(file: string, content: unknown): boolean {
  if (path.basename(file) !== "registry.json") return false
  if (!content || typeof content !== "object") return false
  const includes = (content as { include?: unknown }).include
  return !Array.isArray(includes) || includes.length === 0 || path.basename(file) === "registry.json"
}

Try / catch

try {
  await loadRegistry({ registryFile })
} catch (err) {
  if (err instanceof RegistryError && err.code === "VALIDATION_ERROR" && /must be named registry\.json/.test(err.message)) {
    // rename the file or drop the include field
  }
  throw err
}

Prevention

When it happens

Trigger: Called loadRegistry({ registryFile }) or loadRegistryItem(name, { registryFile }) where the resolved root file contains an 'include' field (usesInclude === true) AND path.basename(rootFile) !== 'registry.json'. E.g. registryFile: 'my-registry.json' with {"include": ["./ui/registry.json"]}.

Common situations: Renaming the root registry file from registry.json to something project-specific (e.g. shadcn-registry.json, app-registry.json) while keeping the include field. Copying a registry config from a sub-package to the repo root without renaming. Migrating from a flat registry to a split one and forgetting the rename.

Related errors


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