shadcn-ui/ui · error · RegistryParseError

PARSE_ERROR

PARSE_ERROR

Error message

Failed to parse registry item: ${item}

What it means

Thrown by fetchRegistryLocal when a local file was read and JSON.parse succeeded, but registryItemSchema.parse failed. RegistryParseError wraps the ZodError (printed in the message) and points at the registry-item schema. The file exists and is valid JSON; its contents just do not match a single registry item.

Source

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

  return `${url}:${headersHash}`
}

export async function fetchRegistryLocal(filePath: string) {
  try {
    // Handle tilde expansion for home directory
    let expandedPath = filePath
    if (filePath.startsWith("~/")) {
      expandedPath = path.join(homedir(), filePath.slice(2))
    }

    const resolvedPath = path.resolve(expandedPath)
    const content = await fs.readFile(resolvedPath, "utf8")
    const parsed = JSON.parse(content)

    try {
      return registryItemSchema.parse(parsed)
    } catch (error) {
      throw new RegistryParseError(filePath, error)
    }
  } catch (error) {
    // Check if this is a file not found error
    if (
      error instanceof Error &&
      (error.message.includes("ENOENT") ||
        error.message.includes("no such file"))
    ) {
      throw new RegistryLocalFileError(filePath, error)
    }
    // Re-throw parse errors as-is
    if (error instanceof RegistryParseError) {
      throw error
    }
    // For other errors (like JSON parse errors), throw as local file error
    throw new RegistryLocalFileError(filePath, error)
  }
}

View on GitHub (pinned to efac598707)

Solutions

  1. Read the printed ZodError issues to find the failing field on the item.
  2. Confirm the file is a single item (has name, type, files), not a catalog (which has items[]).
  3. Validate against https://ui.shadcn.com/schema/registry-item.json.
  4. Use loadRegistry/loadRegistryItem for catalog files instead of fetchRegistryLocal.

Example fix

// before: local item file missing required 'type'
{ "name": "button", "files": [] }

// after
{
  "name": "button",
  "type": "registry:ui",
  "files": [{ "path": "button.tsx", "type": "registry:ui", "target": "" }]
}
Defensive patterns

Strategy: validation

Validate before calling

import { registryItemSchema } from "@/src/schema";
import * as fs from "fs/promises";

async function validateLocalItem(filePath: string) {
  const json = JSON.parse(await fs.readFile(filePath, "utf8"));
  const result = registryItemSchema.safeParse(json);
  if (!result.success) {
    throw new Error(`Item schema error: ${result.error.message}`);
  }
  return result.data;
}

Type guard

function isRegistryItem(json: unknown): boolean {
  return registryItemSchema.safeParse(json).success;
}

Try / catch

try {
  await fetchRegistryLocal(filePath);
} catch (err) {
  if (err instanceof RegistryParseError) {
    // err.parseError holds the ZodError; show field-level issues to fix the file
  }
  throw err;
}

Prevention

When it happens

Trigger: Pointing fetchRegistryLocal at a registry catalog JSON (which has 'items[]') instead of a single registry-item JSON, or at a hand-written item missing required fields (name, type, files with required keys).

Common situations: Confusing a catalog file for an item file, editing a local item JSON and dropping a required field, or schema drift after upgrading the CLI's registry-item schema.

Understand the failure class

Related errors


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