{"record":{"id":"abfe6caadc727c5b","repo":"JuliusBrussee/caveman","slug":"invalid-package","errorCode":null,"errorMessage":"invalid package","messagePattern":"invalid package","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/source-graph.ts","lineNumber":214,"sourceCode":"    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    }\n  }\n}\n\nfunction barePackageName(specifier: string): string {\n  const parts = specifier.split(\"/\");\n  if (specifier.startsWith(\"@\")) {\n    if (parts.length < 2 || parts[1] === \"\") throw new Error(\"invalid scoped package\");\n    return `${parts[0]}/${parts[1]}`;\n  }\n  if (parts[0] === \"\") throw new Error(\"invalid package\");\n  return parts[0]!;\n}\n\nfunction resolvePackageExport(exportsValue: unknown, subpath: string): string | undefined {\n  if (typeof exportsValue === \"string\" || Array.isArray(exportsValue)) {\n    return subpath === \".\" ? resolveConditionalExport(exportsValue) : undefined;\n  }\n  if (!isRecord(exportsValue)) return undefined;\n  const keys = Object.keys(exportsValue);\n  if (!keys.some((key) => key.startsWith(\".\"))) {\n    return subpath === \".\" ? resolveConditionalExport(exportsValue) : undefined;\n  }\n  if (Object.hasOwn(exportsValue, subpath)) {\n    return resolveConditionalExport(exportsValue[subpath]);\n  }\n  const patterns = keys\n    .filter((key) => key.startsWith(\"./\") && key.includes(\"*\"))\n    .sort((left, right) => right.length - left.length);","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/source-graph.ts#L196-L232","documentation":"barePackageName() throws \"invalid package\" when the specifier's first path segment is empty — concretely, specifiers starting with \"/\" (absolute paths). The source graph treats leading-\"/\" imports as malformed bare specifiers rather than resolvable paths; imports must be relative (./ or ../) or bare package names.","triggerScenarios":"A source file contains import \"/src/lib/foo\" — an absolute filesystem path used as a module specifier.","commonSituations":"Configuring a bundler/TS `baseUrl` or `paths` style that allows absolute-looking specifiers, then building with this framework which has no path-mapping support; porting code from bundlers that resolve /-prefixed imports.","solutions":["Rewrite absolute specifiers as real relative imports (./ or ../) from each importing file.","Remove reliance on TS `baseUrl`/`paths` non-relative mappings for files that will enter the locked source graph.","If you need path aliases, resolve them to relative specifiers in a pre-build step."],"exampleFix":"// before\nimport { helper } from \"/src/lib/helper\";\n\n// after\nimport { helper } from \"./lib/helper\";","handlingStrategy":"type-guard","validationCode":"function isLockableSpecifier(spec: string): boolean {\n  return spec.startsWith(\"./\") || spec.startsWith(\"../\") || !spec.startsWith(\"/\");\n}\nif (!isLockableSpecifier(spec)) throw new Error(`non-lockable specifier: ${spec}`);","typeGuard":"const isImportableSpecifier = (spec: string): boolean =>\n  !spec.startsWith(\"/\"); // reject absolute-path specifiers","tryCatchPattern":null,"preventionTips":["Avoid TS baseUrl-style absolute imports in code destined for the locked graph.","Configure an eslint rule (import/no-absolute-path) to catch \"/\"-prefixed imports.","Prefer relative or package specifiers exclusively."],"tags":["build","specifier","path-alias","imports"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}