shadcn-ui/ui · error · RegistryLocalFileError

LOCAL_FILE_ERROR

LOCAL_FILE_ERROR

Error message

Failed to read local registry file: ${filePath}

What it means

Thrown by fetchRegistryLocal in the outer catch when the underlying error message indicates the file does not exist (ENOENT or 'no such file'). RegistryLocalFileError wraps the original filesystem error and the resolved/expanded path that was attempted.

Source

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

    }

    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. Print process.cwd() and confirm the resolved path exists.
  2. Use an absolute path or ensure you run from the directory containing the file.
  3. Verify '~/...' paths expand to the intended HOME.
  4. Create the file or fix the typo in the path.

Example fix

// before
fetchRegistryLocal("./registries/buton.json")  // typo

// after
fetchRegistryLocal("./registries/button.json")
Defensive patterns

Strategy: validation

Validate before calling

import * as fs from "fs";
import path from "path";

function assertFileExists(filePath: string, cwd = process.cwd()) {
  const resolved = filePath.startsWith("~/")
    ? path.join(process.env.HOME ?? "", filePath.slice(2))
    : path.resolve(cwd, filePath);
  if (!fs.existsSync(resolved)) {
    throw new Error(`Registry file not found: ${resolved} (from ${filePath})`);
  }
}

Type guard

import * as fs from "fs";
function localRegistryFileExists(filePath: string): boolean {
  try { return fs.existsSync(require("path").resolve(filePath)); } catch { return false; }
}

Try / catch

try {
  await fetchRegistryLocal(filePath);
} catch (err) {
  if (err instanceof RegistryLocalFileError && /ENOENT|no such file/.test(err.message)) {
    // show the resolved path and the cwd used, then prompt for the correct path
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling fetchRegistryLocal with a path that does not exist on disk (after tilde expansion and path.resolve), a typo'd filename, or running from the wrong working directory so the relative path misses.

Common situations: Wrong cwd, path passed before the file was created, '~/' expansion pointing at an unexpected HOME, or a path that was correct in a different checkout.

Related errors


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