{"record":{"id":"791faa9a269af499","repo":"JuliusBrussee/caveman","slug":"caveman-build-unresolved-package-dependency-jso","errorCode":null,"errorMessage":"caveman build: unresolved package dependency ${JSON.stringify(dependency)}","messagePattern":"caveman build: unresolved package dependency (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/source-graph.ts","lineNumber":186,"sourceCode":"  const packageJSON = JSON.parse(await readFile(packageJSONPath, \"utf8\")) as {\n    dependencies?: Record<string, unknown>;\n    optionalDependencies?: Record<string, unknown>;\n    peerDependencies?: Record<string, unknown>;\n  };\n  await collectPackageFiles(canonicalRoot, files);\n  const required = new Set(Object.keys(packageJSON.dependencies ?? {}));\n  const optional = new Set([\n    ...Object.keys(packageJSON.optionalDependencies ?? {}),\n    ...Object.keys(packageJSON.peerDependencies ?? {}),\n  ]);\n  for (const dependency of [...new Set([...required, ...optional])].sort()) {\n    try {\n      const childPackageJSON = findPackageJSON(dependency, pathToFileURL(packageJSONPath));\n      if (childPackageJSON === undefined) throw new Error(\"package not found\");\n      await collectPackageClosure(dirname(childPackageJSON), files, visitedRoots);\n    } catch (error) {\n      if (!required.has(dependency)) continue;\n      throw new Error(`caveman build: unresolved package dependency ${JSON.stringify(dependency)}`, {\n        cause: error,\n      });\n    }\n  }\n}\n\nasync function collectPackageFiles(directory: string, files: Set<string>): Promise<void> {\n  const entries = await opendir(directory);\n  for await (const entry of entries) {\n    if (entry.name === \"node_modules\" || entry.name === \".git\") continue;\n    const path = resolve(directory, entry.name);\n    if (entry.isDirectory()) {\n      await collectPackageFiles(path, files);\n    } else if (entry.isFile()) {\n      files.add(path);\n    } else if (entry.isSymbolicLink()) {\n      throw new Error(`caveman build: package artifact symlink is not lockable: ${JSON.stringify(path)}`);\n    }","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/source-graph.ts#L168-L204","documentation":"The user-facing wrapper error thrown by collectPackageClosure when a REQUIRED dependency (in dependencies/devDependencies, not optional) cannot be resolved during closure expansion. It names the dependency in the message and attaches the underlying resolution error as `cause`. Optional dependencies that fail are intentionally skipped and never reach this throw.","triggerScenarios":"collectPackageClosure (recursively, via expandSourceGraph) encounters a required dependency whose package.json cannot be found, or whose recursive closure threw; the catch block rethrows because `required.has(dependency)` is true.","commonSituations":"Fresh checkout without install; corrupted node_modules; registry package that removed a transitive dependency; lockfile out of sync with package.json; offline install with missing cache.","solutions":["Read the `cause` to see the underlying failure, then fix that root issue.","Reinstall dependencies cleanly (rm -rf node_modules package-lock.json && npm install).","Pin/adjust versions so the named dependency is actually published and available at the required range.","If the dependency is genuinely optional for your build, move it to optionalDependencies."],"exampleFix":"// before: lockfile references a yanked version\n\"some-dep\": \"npm:some-dep@2.0.0\" // yanked\n\n// after\n\"some-dep\": \"^2.1.0\" // then reinstall","handlingStrategy":"try-catch","validationCode":"import { createRequire } from \"node:module\";\nfunction requireDepsResolvable(pkgJsonPath) {\n  const pkg = require(pkgJsonPath);\n  const req = createRequire(pkgJsonPath);\n  return Object.keys({ ...pkg.dependencies, ...pkg.devDependencies }).filter((d) => { try { req.resolve(d); return false; } catch { return true; } });\n}","typeGuard":"null","tryCatchPattern":"try {\n  await graph.expand();\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith(\"caveman build: unresolved package dependency\")) {\n    const dep = JSON.parse(e.message.split(\"dependency \")[1] ?? '\"\"');\n    console.error(`Install or fix required dependency: ${dep}`);\n  }\n  throw e;\n}","preventionTips":["Keep lockfile and package.json in sync (CI check with npm ls).","Run npm ls / pnpm ls to detect broken trees before building.","Prefer versions that exist and aren't yanked; verify ranges against the registry."],"tags":["dependency-closure","build","module-resolution"],"backgroundTag":"missing-dependency","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}