{"record":{"id":"e2f4e6af4de5a259","repo":"JuliusBrussee/caveman","slug":"caveman-agent-file-path-is-required","errorCode":null,"errorMessage":"caveman agent: file path is required","messagePattern":"caveman agent: file path is required","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/primitives.ts","lineNumber":21,"sourceCode":"  StandardJSONSchemaV1,\n  StandardSchemaV1,\n} from \"@standard-schema/spec\";\n\nexport const AUTO = Symbol.for(\"@caveman-ai/agent:auto\");\nexport type Auto = { readonly kind: \"auto\"; readonly [AUTO]: true };\n\nexport function auto(): Auto {\n  return Object.freeze({ kind: \"auto\", [AUTO]: true as const });\n}\n\nexport interface FileSource {\n  readonly kind: \"file\";\n  readonly path: string;\n}\n\nexport function file(path: string): FileSource {\n  if (typeof path !== \"string\" || path.trim() === \"\") {\n    throw new Error(\"caveman agent: file path is required\");\n  }\n  return Object.freeze({ kind: \"file\", path });\n}\n\nexport const schema = {\n  any: () => Type.Any(),\n  array: <T extends TSchema>(items: T) => Type.Array(items),\n  boolean: () => Type.Boolean(),\n  integer: () => Type.Integer(),\n  literal: <T extends string | number | boolean>(value: T) => Type.Literal(value),\n  number: () => Type.Number(),\n  object: <T extends Record<string, TSchema>>(properties: T) => Type.Object(properties),\n  optional: <T extends TSchema>(value: T) => Type.Optional(value),\n  string: () => Type.String(),\n  union: <T extends TSchema[]>(values: [...T]) => Type.Union(values),\n};\n\nexport type ToolEffect = \"read\" | \"write\" | \"idempotent\" | \"external\";","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/primitives.ts#L3-L39","documentation":"file(path) constructs a frozen FileSource descriptor ({ kind: \"file\", path }) used to mark tool outputs or references backed by files. It refuses anything that is not a non-empty string after trimming, because an empty/whitespace path would produce a meaningless artifact reference. The check is on the argument's shape, not on filesystem existence.","triggerScenarios":"Calling file(\"\"), file(\"   \"), or file(undefined/null/number) — commonly when a computed filename turns out to be empty because an upstream variable was undefined.","commonSituations":"Passing options.outputFile straight from CLI args where the flag was omitted, template strings that interpolate undefined (file(`${dir}/${name}`) with name undefined yields \"dir/undefined\" — that passes but is a smell; fully empty yields the throw), or destructuring a missing field.","solutions":["Guard before calling: if (!path?.trim()) throw your own descriptive error naming the missing option","Default the value: file(path ?? \"out.txt\")","Fix the upstream variable that produced the empty string (usually an undefined option)","Add schema validation on your CLI/config layer so empty paths fail early with context"],"exampleFix":"// before\nconst src = file(args.file); // args.file is undefined when flag omitted\n\n// after\nif (!args.file?.trim()) throw new Error(\"--file is required\");\nconst src = file(args.file);","handlingStrategy":"validation","validationCode":"if (typeof path !== \"string\" || path.trim() === \"\") {\n  throw new Error(\"output file path is required (did you forget --file?)\");\n}\nconst src = file(path);","typeGuard":"const isNonEmptyString = (v: unknown): v is string =>\n  typeof v === \"string\" && v.trim() !== \"\";","tryCatchPattern":null,"preventionTips":["Mark file sources as required in your CLI/config schema so empties fail with context","Type the parameter as string in your own wrappers — file(path: string) already narrows most misuse","Watch for template strings interpolating undefined variables"],"tags":["validation","file-artifacts","api-misuse","typescript"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}