{"record":{"id":"409591381331725d","repo":"JuliusBrussee/caveman","slug":"caveman-build-unresolved-source-dependency-json","errorCode":null,"errorMessage":"caveman build: unresolved source dependency ${JSON.stringify(specifier)}","messagePattern":"caveman build: unresolved source dependency (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/source-graph.ts","lineNumber":57,"sourceCode":"      ...esmSourceSpecifiers(typescript.lexableSource, path),\n      ...typescript.specifiers,\n      ...legacySourceSpecifiers(source, path, code),\n    ]);\n    for (const specifier of specifiers) {\n      if (BUILTINS.has(specifier)) continue;\n      const bare = !specifier.startsWith(\".\");\n      if (bare && !includeBareDependencies) continue;\n      let base: string;\n      let packageRoot: string | undefined;\n      if (bare) {\n        packageRoot = dependencyPackageRoot(specifier, path);\n        try {\n          base = createRequire(path).resolve(specifier);\n        } catch (requireError) {\n          try {\n            base = await resolveImportOnlyDependency(specifier, path);\n          } catch {\n            throw new Error(\n              `caveman build: unresolved source dependency ${JSON.stringify(specifier)}`,\n              { cause: requireError },\n            );\n          }\n        }\n      } else {\n        base = resolve(dirname(path), specifier);\n      }\n      const candidates = extname(base)\n        ? explicitImportCandidates(base, path)\n        : [\n          base,\n          ...RESOLUTION_EXTENSIONS.map((extension) => base + extension),\n          ...SOURCE_EXTENSIONS.map((extension) => resolve(base, `index${extension}`)),\n        ];\n      let found: string | undefined;\n      for (const candidate of candidates) {\n        try {","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/source-graph.ts#L39-L75","documentation":"While building the source graph, a bare (package) import specifier could be resolved neither by Node's createRequire resolution nor by the ESM import-only fallback. The build lock must hash every reachable file of every dependency, so an unresolvable bare import aborts the build with the failing specifier embedded in the message (and the require error as cause).","triggerScenarios":"A project source file imports a package that is not installed, is installed in a layout Node cannot resolve from that importer, or exposes no matching entry in its exports map for the importer's conditions.","commonSituations":"Missing dependency in package.json after cloning (no install), a typo'd package name, an import of a subpath the package's exports map does not expose, or a pnpm hoisting layout where the package is not declared as a direct dependency.","solutions":["Run the package manager install (pnpm install / npm install) so the specifier resolves from the importing file.","Check the exact specifier in the error message against package.json dependencies — typos and missing subpath exports are the most common cause.","If the import is conditional/optional, guard it behind a resolvable path or declare the dependency properly instead of relying on hoisting."],"exampleFix":"// before: package.json lacks the dep, source has:\nimport { foo } from \"some-dep/sub\";\n\n// after: add the dependency\n// pnpm add some-dep   (and verify \"some-dep/sub\" is in its exports map)","handlingStrategy":"validation","validationCode":"import { createRequire } from \"node:module\";\nasync function bareImportResolves(specifier: string, importer: string): Promise<boolean> {\n  try {\n    createRequire(importer).resolve(specifier);\n    return true;\n  } catch {\n    try {\n      await import(/* specifier probe */ specifier); // or use import.meta.resolve when available\n      return true;\n    } catch { return false; }\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await buildSourceGraph(root);\n} catch (error) {\n  if (error instanceof Error && error.message.startsWith(\"caveman build: unresolved source dependency\")) {\n    // specifier is in the message; run install or fix the import\n  } else throw error;\n}","preventionTips":["Install dependencies before building; never rely on hoisting for undeclared packages.","Verify subpath imports against the package's exports map.","Run tsc --noEmit first — unresolvable bare imports surface there too."],"tags":["build","dependencies","resolution","esm"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}