{"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":"exception","errorClass":"Error","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/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/cli.ts#L987-L1023","documentation":"Thrown by `loadBuildInputs` for every CLI command that loads build config. It imports `caveman.config.ts` (or the passed path), reads the `default` or named `config` export, and hard-requires `config.lock === \"strict\"` and `config.sandbox === \"required\"`. Anything else — wrong export shape, missing config, or lenient settings — fails the build immediately: the framework only produces locks for strict-lock, required-sandbox builds.","triggerScenarios":"A `caveman.config.ts` exporting `{ lock: \"loose\" }` or `{ sandbox: \"host\" }` or omitting either field; exporting the config under a name that is neither `default` nor `config`; pointing `--config` at a file whose export is a plain object without the two required literal values.","commonSituations":"Copy-pasting a config template from an older version that defaulted these fields; switching sandbox to `host` for a coding agent and then trying the locked build path (host mode is lock-ineligible by design); typo in the export name (`export const buildConfig = ...` is not read).","solutions":["Set both literals in the config export: `lock: \"strict\"`, `sandbox: \"required\"`.","Confirm the export is `export default` or `export const config`.","If you intentionally need host sandbox (coding agents), use the code.ts session surface instead of the locked build CLI — `compile` refuses host mode anywhere in the graph.","Check you passed the right config path as args[0]; the default is `caveman.config.ts` at the project root."],"exampleFix":"// before\ndefault export defineConfig({ lock: \"strict\", sandbox: \"host\" });\n\n// after\nexport default defineConfig({ lock: \"strict\", sandbox: \"required\" });","handlingStrategy":"validation","validationCode":"type BuildConfigShape = { lock?: unknown; sandbox?: unknown };\n\nfunction configIsValid(config: BuildConfigShape | undefined): boolean {\n  return !!config && config.lock === \"strict\" && config.sandbox === \"required\";\n}\n// assert configIsValid((await import(configPath)).default) before invoking the CLI","typeGuard":"function isStrictBuildConfig(v: unknown): v is { lock: \"strict\"; sandbox: \"required\" } {\n  return typeof v === \"object\" && v !== null &&\n    (v as { lock?: unknown }).lock === \"strict\" &&\n    (v as { sandbox?: unknown }).sandbox === \"required\";\n}","tryCatchPattern":"try {\n  await build(args);\n} catch (error) {\n  if (error instanceof Error && error.message.includes(\"strict lock and required sandbox\")) {\n    // fix caveman.config.ts export and retry\n  } else throw error;\n}","preventionTips":["Use the framework's defineConfig helper so literal types catch typos at compile time.","Never use host sandbox with the locked build path; use the coding-session surface instead.","Export config as `default` or named `config` only."],"tags":["config","build","sandbox","cli"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}