{"record":{"id":"64a2bf4f33f0a067","repo":"JuliusBrussee/caveman","slug":"caveman-build-invalid-caveman-provider-json","errorCode":null,"errorMessage":"caveman build: invalid .caveman/provider.json","messagePattern":"caveman build: invalid \\.caveman/provider\\.json","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/cli.ts","lineNumber":1360,"sourceCode":"  };\n}\n\nfunction evalDynamicKinds(evals: readonly EvalDefinition[]): ReadonlySet<ContextKind> {\n  const kinds = new Set<ContextKind>();\n  if (evals.some((fixture) => fixture.quality.some((grader) => grader.type === \"tool_called\"))) {\n    kinds.add(\"history\");\n    kinds.add(\"tool_result\");\n  }\n  return kinds;\n}\n\nfunction localProviderModel(root: string): string | undefined {\n  try {\n    const parsed = JSON.parse(readFileSync(resolve(root, \".caveman/provider.json\"), \"utf8\")) as { model?: unknown };\n    return typeof parsed.model === \"string\" ? parsed.model : undefined;\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n    throw new Error(\"caveman build: invalid .caveman/provider.json\");\n  }\n}\n\nfunction detectedModel(): string {\n  const configured = [\n    process.env.ANTHROPIC_API_KEY && \"anthropic/claude-haiku-4-5\",\n    process.env.OPENAI_API_KEY && \"openai/gpt-5.4-mini\",\n    (process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY) && \"google/gemini-2.5-flash\",\n  ].filter((value): value is string => typeof value === \"string\");\n  if (configured.length !== 1) {\n    throw new Error(\"caveman build: set CAVE_MODEL when zero or multiple provider credentials exist\");\n  }\n  return configured[0]!;\n}\n\nasync function loadAgent(path: string): Promise<AgentDefinition> {\n  return agentFromImported(await importFresh(path));\n}","sourceCodeStart":1342,"sourceCodeEnd":1378,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/cli.ts#L1342-L1378","documentation":"localProviderModel in packages/agent/src/cli.ts reads .caveman/provider.json to detect a configured model. If the file parses as JSON but readFileSync fails with a non-ENOENT error, or JSON.parse throws a syntax error, the function throws 'caveman build: invalid .caveman/provider.json'. Only a completely absent file is tolerated (returns undefined).","triggerScenarios":"Running 'caveman build' when .caveman/provider.json exists but contains invalid JSON (trailing comma, truncated write), or when reading it fails with a permission/IO error (EACCES, EISDIR) rather than ENOENT.","commonSituations":"A partially written or hand-edited provider.json left invalid JSON behind; the path .caveman/provider.json is actually a directory; restrictive file permissions after copying the repo as another user; editor swap/temp files renamed incorrectly.","solutions":["Validate and repair the JSON: run `node -e \"JSON.parse(require('fs').readFileSync('.caveman/provider.json','utf8'))\"` and fix syntax errors (or delete the file if you do not need a pinned model).","Ensure .caveman/provider.json is a regular file, not a directory or symlink to a missing target.","Fix file permissions so the current user can read it (chmod 644 .caveman/provider.json).","Set CAVE_MODEL explicitly so provider detection does not depend on this file.","Remove a stale/truncated provider.json and let the build re-detect the model from provider credentials."],"exampleFix":"// before (invalid JSON)\n{ \"model\": \"anthropic/claude-haiku-4-5\", }\n// after\n{ \"model\": \"anthropic/claude-haiku-4-5\" }","handlingStrategy":"try-catch","validationCode":"const fs = require(\"fs\");\nif (fs.existsSync(\".caveman/provider.json\")) {\n  try { JSON.parse(fs.readFileSync(\".caveman/provider.json\", \"utf8\")); }\n  catch { console.error(\"provider.json is not valid JSON — fix or delete it\"); }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await build();\n} catch (e) {\n  if (e.message.includes(\"invalid .caveman/provider.json\")) {\n    console.error(\"Repair or remove .caveman/provider.json, or set CAVE_MODEL.\");\n  } else throw e;\n}","preventionTips":["Validate .caveman/provider.json with a JSON linter after every manual edit.","Write the file atomically (write tmp file, rename) to avoid truncated JSON.","Set CAVE_MODEL explicitly so you never depend on provider.json parsing.","Ensure the path is a regular readable file, not a directory or mis-modeled symlink."],"tags":["json","config","cli"],"backgroundTag":"json-parse-error","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}