{"record":{"id":"8f534bb3e091d28d","repo":"JuliusBrussee/caveman","slug":"cave-execution-authorization-ambiguous-8f534b","errorCode":"cave_execution_authorization_ambiguous","errorMessage":"cave_execution_authorization_ambiguous","messagePattern":"cave_execution_authorization_ambiguous","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/runtime.ts","lineNumber":1070,"sourceCode":"\nasync function* streamAgentInternal(\n  definition: AgentDefinition,\n  input: string,\n  options: InternalRunOptions,\n  executionContext: InternalExecutionContext,\n): AsyncGenerator<CavemanRunEvent> {\n  if (options.maxSubagentInvocations !== undefined &&\n      (!Number.isSafeInteger(options.maxSubagentInvocations) || options.maxSubagentInvocations <= 0 ||\n        options.maxSubagentInvocations > ABSOLUTE_SUBAGENT_INVOCATION_LIMIT)) {\n    throw new Error(\"cave_subagent_invocation_limit_invalid\");\n  }\n  if (options.maxConcurrentSubagents !== undefined &&\n      (!Number.isSafeInteger(options.maxConcurrentSubagents) || options.maxConcurrentSubagents <= 0 ||\n        options.maxConcurrentSubagents > ABSOLUTE_SUBAGENT_INVOCATION_LIMIT)) {\n    throw new Error(\"cave_subagent_concurrency_limit_invalid\");\n  }\n  if (options.lockedBuild !== undefined && options.candidatePlan !== undefined) {\n    throw new Error(\"cave_execution_authorization_ambiguous\");\n  }\n  // Budget shape is settled before anything else happens: an ambiguous or\n  // unbounded budget must fail at run() start, not after the first dollar.\n  // maxCostUsd and budget are two different contracts for the same money —\n  // one terminates with an error, the other returns a planned partial result —\n  // so carrying both would leave the run's own stop semantics undecided.\n  if (options.budget !== undefined && options.maxCostUsd !== undefined) {\n    throw new Error(\"cave_budget_conflicting_cap\");\n  }\n  const budgetMeter = executionContext.budgetMeter ?? (options.budget === undefined\n    ? undefined\n    : new BudgetMeter(normalizeRunBudget(options.budget)));\n  if (options.deadlineMs !== undefined &&\n      (!Number.isSafeInteger(options.deadlineMs) || options.deadlineMs <= 0)) {\n    throw new Error(\"cave_run_deadline_invalid\");\n  }\n  if (options.maxSubagentDepth !== undefined &&\n      (!Number.isSafeInteger(options.maxSubagentDepth) || options.maxSubagentDepth <= 0 ||","sourceCodeStart":1052,"sourceCodeEnd":1088,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/runtime.ts#L1052-L1088","documentation":"Execution authorization is ambiguous when both a locked build (lockedBuild) and a candidate plan (candidatePlan) are supplied: the runtime cannot decide whether to execute a compiled/locked identity or search over a candidate. One and only one execution authorization may be present, so the run fails closed at start.","triggerScenarios":"Passing both options.lockedBuild and options.candidatePlan in InternalRunOptions to streamAgent/runAgent in the same call.","commonSituations":"Internal compiler/CLI code paths merging option objects where one layer adds a lockedBuild while a default carries candidatePlan; accidental spread of two config objects into one options bag.","solutions":["Remove one of the two fields — supply either lockedBuild (locked execution) or candidatePlan (candidate search), never both.","Audit option-object merging/spreads so a default candidatePlan cannot survive when a lockedBuild is set.","If migrating from candidate runs to a locked build, drop candidatePlan explicitly (set to undefined, not just leave in the object when using explicit property checks)."],"exampleFix":"// before\nawait runAgentInternal(def, input, { lockedBuild, candidatePlan, ...rest });\n// after\nawait runAgentInternal(def, input,\n  lockedBuild !== undefined\n    ? { lockedBuild, ...rest }\n    : { candidatePlan, ...rest });","handlingStrategy":"validation","validationCode":"if (opts.lockedBuild !== undefined && opts.candidatePlan !== undefined) {\n  throw new Error(\"lockedBuild and candidatePlan are mutually exclusive\");\n}","typeGuard":"function hasSingleExecutionAuthorization(o) {\n  return !(o.lockedBuild !== undefined && o.candidatePlan !== undefined);\n}","tryCatchPattern":"try {\n  await runAgentInternal(def, input, opts);\n} catch (err) {\n  if (err.message === \"cave_execution_authorization_ambiguous\") {\n    await runAgentInternal(def, input, { ...opts, candidatePlan: undefined });\n  } else throw err;\n}","preventionTips":["Build options objects conditionally: locked build XOR candidate plan.","Avoid spreading multiple config layers that each carry an authorization field.","Explicitly set fields to undefined when a later layer supersedes them."],"tags":["agent-runtime","options","locked-build"],"backgroundTag":"mutually-exclusive-options","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"}