{"record":{"id":"52afed0fe8d9aa61","repo":"JuliusBrussee/caveman","slug":"caveman-build-config-must-use-strict-lock-and-req","errorCode":null,"errorMessage":"caveman build: config must use strict lock and required sandbox","messagePattern":"caveman build: config must use strict lock and required sandbox","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/cli.ts","lineNumber":1005,"sourceCode":"  \"package.json\",\n  \"package-lock.json\",\n  \"npm-shrinkwrap.json\",\n  \"pnpm-lock.yaml\",\n  \"yarn.lock\",\n] as const;\n\nasync function loadBuildInputs(\n  root: string,\n  configPath: string,\n  beforeSourceHash?: (\n    inputs: Omit<LoadedBuildInputs, \"sourceSha256\">,\n  ) => Promise<void>,\n): Promise<LoadedBuildInputs> {\n  const configAbsolute = resolve(root, configPath);\n  const imported = await importFresh(configAbsolute) as { default?: BuildConfig; config?: BuildConfig };\n  const config = imported.default ?? imported.config;\n  if (!config || config.lock !== \"strict\" || config.sandbox !== \"required\") {\n    throw new Error(\"caveman build: config must use strict lock and required sandbox\");\n  }\n  const entryAbsolute = resolve(root, config.entry);\n  const agent = await loadAgent(entryAbsolute);\n  const evalFiles: string[] = [];\n  for await (const path of glob(config.evals, { cwd: root })) evalFiles.push(resolve(root, path));\n  evalFiles.sort();\n  const evals: EvalDefinition[] = [];\n  for (const path of evalFiles) {\n    const module = await importFresh(path) as Record<string, unknown>;\n    for (const value of Object.values(module)) {\n      if (isEval(value)) evals.push(value);\n    }\n  }\n  await beforeSourceHash?.({ config, agent, evals });\n  const sourceFiles = new Set<string>([configAbsolute, entryAbsolute, ...evalFiles]);\n  for (const pattern of SOURCE_PATTERNS) {\n    for await (const path of glob(pattern, { cwd: root })) sourceFiles.add(resolve(root, path));\n  }","sourceCodeStart":987,"sourceCodeEnd":1023,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/cli.ts#L987-L1023","documentation":"loadBuildInputs imports the caveman config and enforces that every build uses lock: \"strict\" and sandbox: \"required\". These are non-negotiable safety invariants of the caveman build system — a config relaxing either is rejected before any agent loading happens. The error fires when the config is missing entirely, or when either field has a different value.","triggerScenarios":"caveman.config.ts omits `lock` or `sandbox`, sets `lock: \"loose\"|\"off\"` or `sandbox: \"optional\"|\"disabled\"`, exports a non-object, or uses an old config shape without these fields.","commonSituations":"Following an outdated tutorial/template that set sandbox to optional; disabling the sandbox locally for debugging and forgetting to revert; hand-written config missing the fields; defineBuild defaults that don't satisfy the strict requirement.","solutions":["Set `lock: \"strict\"` and `sandbox: \"required\"` in the defineBuild() call in caveman.config.ts.","If you copied an old config, update it to the current schema and re-run.","Ensure the config actually exports via default or `config` so the object is seen.","Re-run `npm run build` after fixing."],"exampleFix":"// before\nexport default defineBuild({ lock: \"loose\", sandbox: \"optional\", evals: \"evals/*.eval.ts\", entry: \"src/agent.ts\" });\n// after\nexport default defineBuild({ lock: \"strict\", sandbox: \"required\", evals: \"evals/*.eval.ts\", entry: \"src/agent.ts\" });","handlingStrategy":"validation","validationCode":"const cfg = (await import(\"./caveman.config.ts\")).default;\nif (!cfg || cfg.lock !== \"strict\" || cfg.sandbox !== \"required\") {\n  throw new Error(\"caveman.config.ts must set lock: 'strict' and sandbox: 'required'\");\n}","typeGuard":"const isStrictConfig = (c: unknown): c is BuildConfig & { lock: \"strict\"; sandbox: \"required\" } =>\n  typeof c === \"object\" && c !== null &&\n  (c as BuildConfig).lock === \"strict\" && (c as BuildConfig).sandbox === \"required\";","tryCatchPattern":"try {\n  await loadBuildInputs(root, configPath);\n} catch (err) {\n  if (String(err?.message).includes(\"strict lock and required sandbox\")) {\n    console.error(\"Update caveman.config.ts: defineBuild({ lock: 'strict', sandbox: 'required', ... })\");\n  }\n  throw err;\n}","preventionTips":["Start every new config from the official template that already sets strict/required.","Never disable the sandbox even for local debugging — use a fixture instead.","Type configs with BuildConfig and literal types so invalid values fail at compile time.","Add a repo-level test asserting all configs are strict/required."],"tags":["config","validation","security"],"backgroundTag":"invalid-config-value","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"}