JuliusBrussee/caveman · error
caveman build: unresolved package dependency ${JSON.stringif
Error message
caveman build: unresolved package dependency ${JSON.stringify(dependency)} What it means
While collecting a package's dependency closure, a dependency listed in package.json's dependencies could not be resolved (its package.json was not found). Required dependencies are hard failures; optional and peer dependencies are skipped silently when unresolvable. The failing dependency name is embedded in the error and the underlying cause is attached.
Source
Thrown at packages/agent/src/source-graph.ts:186
const packageJSON = JSON.parse(await readFile(packageJSONPath, "utf8")) as {
dependencies?: Record<string, unknown>;
optionalDependencies?: Record<string, unknown>;
peerDependencies?: Record<string, unknown>;
};
await collectPackageFiles(canonicalRoot, files);
const required = new Set(Object.keys(packageJSON.dependencies ?? {}));
const optional = new Set([
...Object.keys(packageJSON.optionalDependencies ?? {}),
...Object.keys(packageJSON.peerDependencies ?? {}),
]);
for (const dependency of [...new Set([...required, ...optional])].sort()) {
try {
const childPackageJSON = findPackageJSON(dependency, pathToFileURL(packageJSONPath));
if (childPackageJSON === undefined) throw new Error("package not found");
await collectPackageClosure(dirname(childPackageJSON), files, visitedRoots);
} catch (error) {
if (!required.has(dependency)) continue;
throw new Error(`caveman build: unresolved package dependency ${JSON.stringify(dependency)}`, {
cause: error,
});
}
}
}
async function collectPackageFiles(directory: string, files: Set<string>): Promise<void> {
const entries = await opendir(directory);
for await (const entry of entries) {
if (entry.name === "node_modules" || entry.name === ".git") continue;
const path = resolve(directory, entry.name);
if (entry.isDirectory()) {
await collectPackageFiles(path, files);
} else if (entry.isFile()) {
files.add(path);
} else if (entry.isSymbolicLink()) {
throw new Error(`caveman build: package artifact symlink is not lockable: ${JSON.stringify(path)}`);
}View on GitHub (pinned to 27d5a3981a)
Solutions
- Delete node_modules and lockfile-unfriendly state, then reinstall cleanly (rm -rf node_modules && pnpm install).
- Check the named dependency in the error against the lockfile — a lockfile/install mismatch usually explains it.
- If the package genuinely needs the dependency only optionally, its maintainers should move it to optionalDependencies; file an issue rather than patching locally.
Example fix
# before pnpm install --no-optional # or a partial install # after rm -rf node_modules && pnpm install
Defensive patterns
Strategy: validation
Validate before calling
import { createRequire } from "node:module";
import { readFileSync } from "node:fs";
function requiredDepsResolvable(packageDir: string): void {
const pkg = JSON.parse(readFileSync(resolve(packageDir, "package.json"), "utf8"));
const req = createRequire(resolve(packageDir, "index.js"));
for (const dep of Object.keys(pkg.dependencies ?? {})) {
try { req.resolve(`${dep}/package.json`); }
catch { throw new Error(`required dependency missing: ${dep}`); }
}
} Try / catch
try {
await buildSourceGraph(root);
} catch (error) {
if (error instanceof Error && error.message.startsWith("caveman build: unresolved package dependency")) {
// dependency name is quoted; clean reinstall node_modules
} else throw error;
} Prevention
- Clean reinstall when install state looks partial (rm -rf node_modules).
- Do not manually delete packages inside node_modules.
- Keep the lockfile committed so transitive closures are reproducible.
When it happens
Trigger: An installed package's package.json declares a runtime dependency that is missing from node_modules — broken install, pruned store, or a manually-edited package tree.
Common situations: Interrupted or partial pnpm/npm install; node_modules copied between machines; a dependency whose transitive install failed; using --no-optional or aggressive pruning that removed a required transitive package.
Related errors
- caveman build: unresolved source dependency ${JSON.stringify
- package not found
- caveman build: package artifact symlink is not lockable: ${J
- cave_${harness}_upstream_version_unresolvable
- caveman build: dataResidency is not enforced yet; refusing t
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/791faa9a269af499.
Report an issue: GitHub.