{"record":{"id":"3160bcc89cbe4d77","repo":"shadcn-ui/ui","slug":"local-file-error-3160bc","errorCode":"LOCAL_FILE_ERROR","errorMessage":"Failed to read file \"${filePath}\" for registry item \"${itemName}\" (${formatItemSource(source)}). Expected file at ${sourcePath}.","messagePattern":"Failed to read file \"(.+?)\" for registry item \"(.+?)\" \\((.+?)\\)\\. Expected file at (.+?)\\.","errorType":"exception","errorClass":"RegistryLocalFileError","httpStatus":null,"severity":"error","filePath":"packages/shadcn/src/registry/loader.ts","lineNumber":195,"sourceCode":"        sourcePath,\n        source\n      )\n    })\n  )\n\n  return registryItemSchema.parse(registryItem)\n}\n\nasync function readRegistryItemFileContent(\n  itemName: string,\n  filePath: string,\n  sourcePath: string,\n  source: RegistryItemSource | undefined\n) {\n  try {\n    return await fs.readFile(sourcePath, \"utf-8\")\n  } catch (error) {\n    throw new RegistryLocalFileError(sourcePath, error, {\n      message: `Failed to read file \"${filePath}\" for registry item \"${itemName}\" (${formatItemSource(\n        source\n      )}). Expected file at ${sourcePath}.`,\n      context: {\n        itemName,\n        itemFilePath: filePath,\n        sourcePath,\n      },\n      suggestion:\n        \"Make sure the file path is relative to the registry.json file that declares the item.\",\n    })\n  }\n}\n\nfunction rewriteRegistryItemFilePaths(\n  item: RegistryItem,\n  itemSourcesByItem: Map<RegistryItem, RegistryItemSource>,\n  rootDir: string,","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/shadcn-ui/ui/blob/efac5987074af84ece57c367c6dd83387b967022/packages/shadcn/src/registry/loader.ts#L177-L213","documentation":"Thrown by readRegistryItemFileContent when fs.readFile fails on the resolved source path for a registry item's file. This happens during createRegistryItem (loadRegistryItem), after paths have been rewritten relative to the item's source registryDir. The library refuses to emit an item whose declared source file cannot be read, since the file content is required to build the item payload.","triggerScenarios":"Called loadRegistryItem(itemName) where the item declares a 'files' entry whose 'path' does not resolve to an existing file under the declaring registry's directory (registryDir). Triggered when path.resolve(source.registryDir ?? fallbackDir, filePath) points to a missing, unreadable, or permission-denied file.","commonSituations":"Item declares a file path relative to one directory but the registry.json sits in another (e.g. moved registry without updating file paths). Typo in the file path. File deleted but still referenced. Symlink pointing nowhere. Running build from a different cwd than expected, so fallbackDir resolves wrong.","solutions":["Check the error's context.sourcePath and confirm that file actually exists on disk.","Make the item's file path relative to the registry.json that declares the item (not the repo root, not the cwd).","If running programmatically, pass cwd: <dir containing registry.json> so the fallback directory resolves correctly.","Restore the missing file or remove the file entry from the item's 'files' array."],"exampleFix":"// before - registry.json in ./registry/ declares:\n// { \"name\": \"button\", \"files\": [{ \"path\": \"components/Button.tsx\" }] }\n// but the file lives at ./registry/components/Button.tsx\n\n// after - path is relative to the registry.json's own directory\n// { \"name\": \"button\", \"files\": [{ \"path\": \"./components/Button.tsx\" }] }","handlingStrategy":"validation","validationCode":"import * as fs from \"fs/promises\"\nimport * as path from \"path\"\n\nasync function assertItemFilesExist(item: { name: string; files?: { path: string }[] }, registryDir: string) {\n  for (const f of item.files ?? []) {\n    const resolved = path.resolve(registryDir, f.path)\n    await fs.access(resolved)\n  }\n}\n\n// before loadRegistryItem:\nfor (const item of catalog.items) {\n  await assertItemFilesExist(item, registryDir)\n}","typeGuard":"function itemHasLocalFiles(item: { files?: { path: string }[] }): boolean {\n  return (item.files ?? []).every((f) => !isUrl(f.path) && !path.isAbsolute(f.path))\n}","tryCatchPattern":"try {\n  await loadRegistryItem(name, { cwd })\n} catch (err) {\n  if (err instanceof RegistryLocalFileError && /Failed to read file/.test(err.message)) {\n    // err.context.sourcePath tells you which file is missing\n  }\n  throw err\n}","preventionTips":["Run the build from a fixed cwd (set explicitly in scripts).","Keep item file paths relative to the declaring registry.json.","Add a pre-build check that walks items and fs.access-es each file."],"tags":["registry","filesystem","item-files","local-file"],"backgroundTag":null,"analyzedSha":"efac5987074af84ece57c367c6dd83387b967022","analyzedAt":"2026-08-12T05:00:50.218Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}