JuliusBrussee/caveman · error
import export not found
Error message
import export not found
What it means
Thrown by resolveImportOnlyDependency when a package's package.json has no `exports` entry matching the requested import specifier subpath, or the resolved target does not start with "./". The library resolves dependencies strictly through the package's declared exports map (Node's export map semantics) and refuses to guess a file path. This means the specifier used in source code is not covered by the package's public export surface.
Solutions
- Check the dependency's package.json `exports` map and import only subpaths it actually declares.
- Update or pin the dependency version to one that exports the subpath you need.
- If you own the dependency, add the missing subpath to its exports map (e.g. "./util": "./dist/util.js").
- If deep import is intentional and legitimate, bypass via a bundler alias or import the file through the package root re-export.
Example fix
// before
import { util } from "somepkg/src/util.js";
// after
import { util } from "somepkg"; // use the package's declared export surface Defensive patterns
Strategy: validation
Validate before calling
import { readFileSync } from "node:fs";
function isExported(pkgDir, name, subpath) {
const pkg = JSON.parse(readFileSync(`${pkgDir}/package.json`, "utf8"));
const key = name === subpath ? "." : `.${subpath.slice(name.length)}`;
const exp = pkg.exports;
if (typeof exp === "string" || Array.isArray(exp)) return key === ".";
return !!exp && Object.prototype.hasOwnProperty.call(exp, key);
} Type guard
function hasExportsField(pkg: unknown): pkg is { exports: Record<string, unknown> } {
return typeof pkg === "object" && pkg !== null && "exports" in pkg && typeof (pkg as any).exports === "object";
} Try / catch
try {
await graph.expand();
} catch (e) {
if (e instanceof Error && e.message === "import export not found") {
console.error("Specifier not covered by the package exports map; fix the import or the exports field.");
}
throw e;
} Prevention
- Only import subpaths listed in the dependency's exports map (check its package.json).
- Pin dependency versions so exports surfaces don't shift under you.
- Prefer root or re-exported imports over deep imports.
When it happens
Trigger: expandSourceGraph resolves an import-only dependency; resolvePackageExport(exports, subpath) returns undefined (subpath not listed in exports, or exports is a string for a non-"." subpath), or the target is not a relative "./" path.
Common situations: Deep-importing an internal file like `pkg/src/util.js` when exports only exposes "."; importing a subpath the package removed in a newer version; package.json lacking an exports field entirely so string-form exports can't serve subpath imports; typos in the subpath.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- caveman build: aliased source loader is not lockable in
- caveman build: computed source dependency is not lockable in
- caveman build: unresolved package dependency
- caveman build: unresolved relative source import
- caveman build: unresolved source dependency
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/12d0d4501542437b.
Report an issue: GitHub.
Appendix: source
Thrown at packages/agent/src/source-graph.ts:135
// Match TypeScript NodeNext extension substitution. Authored TypeScript uses
// runtime-valid .js/.mjs/.cjs specifiers while compiler and loader resolve
// their .ts/.mts/.cts sources.
if (extension === ".js") return [`${stem}.ts`, `${stem}.tsx`, base];
if (extension === ".mjs") return [`${stem}.mts`, base];
if (extension === ".cjs") return [`${stem}.cts`, base];
return [base];
}
async function resolveImportOnlyDependency(specifier: string, importer: string): Promise<string> {
const packageName = barePackageName(specifier);
const packageJSONPath = resolvePackageJSON(packageName, importer);
const packageJSON = JSON.parse(await readFile(packageJSONPath, "utf8")) as {
exports?: unknown;
};
const subpath = specifier === packageName ? "." : `.${specifier.slice(packageName.length)}`;
const target = resolvePackageExport(packageJSON.exports, subpath);
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;View on GitHub (pinned to 3ee70a1026)