{"record":{"id":"d6d431a63b2aa9fc","repo":"JuliusBrussee/caveman","slug":"caveman-build-source-module-syntax-is-not-lexable","errorCode":null,"errorMessage":"caveman build: source module syntax is not lexable in ${JSON.stringify(path)}","messagePattern":"caveman build: source module syntax is not lexable in (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/source-graph.ts","lineNumber":276,"sourceCode":"  return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction isPathWithin(root: string, candidate: string): boolean {\n  const child = relative(root, candidate);\n  return child === \"\" || (!isAbsolute(child) && child !== \"..\" &&\n    !child.startsWith(\"../\") && !child.startsWith(\"..\\\\\"));\n}\n\nfunction esmSourceSpecifiers(source: string, path: string): string[] {\n  let imports: ReturnType<typeof parse>[0];\n  try {\n    [imports] = parse(source, path);\n  } catch (error) {\n    throw new Error(\n      `caveman build: source module syntax is not lexable in ${JSON.stringify(path)}`,\n      { cause: error },\n    );\n  }\n  const specifiers: string[] = [];\n  for (const item of imports) {\n    if (item.d === -2) continue; // import.meta is metadata, not a dependency.\n    if (item.n === undefined) {\n      throw new Error(`caveman build: computed source dependency is not lockable in ${JSON.stringify(path)}`);\n    }\n    specifiers.push(item.n);\n  }\n  return specifiers;\n}\n\nfunction typescriptSourceSyntax(\n  source: string,\n  path: string,","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/source-graph.ts#L258-L294","documentation":"esmSourceSpecifiers() runs es-module-lexer's parse() over a source file and throws this error when parsing itself fails, wrapping the lexer error as cause. If the file cannot be lexed as an ES module, its import graph cannot be extracted, so the source closure is not computable and the build aborts with the file path in the message.","triggerScenarios":"A .js/.mjs file with a genuine syntax error, or syntax the lexer version cannot handle (e.g. very new ECMAScript proposals or malformed code) anywhere in the reachable project graph.","commonSituations":"Building while the working tree has a half-edited file; a tool or codegen step emitting invalid JS; an es-module-lexer version lagging behind bleeding-edge syntax used in sources.","solutions":["Open the path from the error message and fix the syntax error; the cause error carries the lexer's line/column.","Run your normal lint/tsc pass before building so broken files fail there first.","If the syntax is valid-but-new, pin a newer framework/lexer version that supports it."],"exampleFix":"// before: src/broken.js\nexport const = bad syntax;\n\n// after\nexport const value = \"fixed\";","handlingStrategy":"try-catch","validationCode":"import { parse } from \"es-module-lexer\";\nfunction isLexable(source: string, path: string): boolean {\n  try { parse(source, path); return true; } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await buildSourceGraph(root);\n} catch (error) {\n  if (error instanceof Error && error.message.includes(\"source module syntax is not lexable\")) {\n    // file path is in the message; error.cause carries the lexer error with line/column\n  } else throw error;\n}","preventionTips":["Run lint/tsc before build so syntax errors fail early.","Avoid committing half-edited files; use --fix or revert before building.","The cause error has the lexer's position — read error.cause, not just the wrapper."],"tags":["build","syntax-error","es-module-lexer","parsing"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}