JuliusBrussee/caveman · error

package not found

Error message

package not found

What it means

resolvePackageJSON walks package.json files up from the importer looking for the named package and throws "package not found" when none locates it. This is the resolution step behind bare-import handling in the source graph: before a dependency's closure can be collected, its physical package root must be found. The error usually surfaces as the cause of the more specific caveman build errors.

Source

Thrown at packages/agent/src/source-graph.ts:152

  if (target === undefined || !target.startsWith("./")) {
    throw new Error("import export not found");
  }
  const packageRoot = dirname(packageJSONPath);
  const absolute = resolve(packageRoot, target);
  const relativeTarget = relative(packageRoot, absolute);
  if (relativeTarget === ".." || relativeTarget.startsWith("../") || relativeTarget.startsWith("..\\")) {
    throw new Error("package export escapes package root");
  }
  return absolute;
}

function dependencyPackageRoot(specifier: string, importer: string): string {
  return dirname(resolvePackageJSON(barePackageName(specifier), importer));
}

function resolvePackageJSON(packageName: string, importer: string): string {
  const packageJSONPath = findPackageJSON(packageName, pathToFileURL(importer));
  if (packageJSONPath === undefined) throw new Error("package not found");
  return packageJSONPath;
}

async function collectPackageClosure(
  packageRoot: string,
  files: Set<string>,
  visitedRoots: Set<string>,
): Promise<void> {
  const canonicalRoot = await realpath(packageRoot);
  if (visitedRoots.has(canonicalRoot)) return;
  visitedRoots.add(canonicalRoot);
  // Resolve dependency edges from the physical package location. pnpm exposes
  // the project dependency as a symlink, while its private dependency links
  // live beside the physical package under node_modules/.pnpm.
  const packageJSONPath = resolve(canonicalRoot, "package.json");
  const packageJSON = JSON.parse(await readFile(packageJSONPath, "utf8")) as {
    dependencies?: Record<string, unknown>;
    optionalDependencies?: Record<string, unknown>;

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Install dependencies (pnpm install) so the package exists in node_modules near the importer.
  2. Declare the package as a direct dependency of the importing package — pnpm's isolated layout hides undeclared packages.
  3. Verify the package name in the specifier matches the installed package's declared name.

Example fix

# before: import "left-pad" without declaring it (works only via hoisting)

# after
pnpm add left-pad
Defensive patterns

Strategy: validation

Validate before calling

import { createRequire } from "node:module";
function packageResolvable(pkg: string, importer: string): boolean {
  try {
    createRequire(importer).resolve(`${pkg}/package.json`);
    return true;
  } catch { return false; }
}

Try / catch

try {
  await buildSourceGraph(root);
} catch (error) {
  const isPkgMissing = (e: unknown) => e instanceof Error && e.message === "package not found";
  if (isPkgMissing(error) || isPkgMissing((error as Error)?.cause)) {
    // install the missing package or declare it as a direct dependency
  } else throw error;
}

Prevention

When it happens

Trigger: dependencyPackageRoot() is called for a bare specifier whose package is not present in any node_modules reachable from the importing file.

Common situations: Dependency not installed (fresh clone without install), pnpm strict node_modules where an undeclared package is not visible to the importer, or a package.json name mismatch after a rename.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/12414e210e6ab3dd. Report an issue: GitHub.