{"record":{"id":"4135bea9d9548534","repo":"JuliusBrussee/caveman","slug":"cave-subagent-wallet-unavailable","errorCode":"cave_subagent_wallet_unavailable","errorMessage":"cave_subagent_wallet_unavailable","messagePattern":"cave_subagent_wallet_unavailable","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/runtime.ts","lineNumber":3897,"sourceCode":"  const depthLimit = Math.min(\n    parentOptions.maxSubagentDepth ?? DEFAULT_SUBAGENT_DEPTH_LIMIT,\n    ABSOLUTE_SUBAGENT_DEPTH_LIMIT,\n  );\n  if (depth + 1 > depthLimit) throw new Error(\"cave_subagent_depth_limit\");\n  // The wallet is carved here, still synchronously, for the same reason: two\n  // subagents dispatched in one turn must not both be funded out of the same\n  // remaining budget.\n  const walletAmount = parentMeter === undefined\n    ? undefined\n    : parentMeter.denomination === \"usd\" ? runtime.maxCostUsd : runtime.maxTokens;\n  if (parentMeter !== undefined && walletAmount === undefined) {\n    throw new Error(\"cave_subagent_wallet_denomination_unavailable\");\n  }\n  const carve = parentMeter === undefined || walletAmount === undefined\n    ? undefined\n    : parentMeter.carve(walletAmount);\n  if (parentMeter !== undefined && carve === undefined) {\n    throw new Error(\"cave_subagent_wallet_unavailable\");\n  }\n  let releaseAdmission: (() => void) | undefined;\n  try {\n    releaseAdmission = admitSubagent(executionContext.invocationState);\n    return await runSubagent({\n      toolDefinition,\n      runtime,\n      task,\n      signal,\n      parentOptions,\n      usage,\n      executionContext,\n      depth,\n      childMeter: carve?.child,\n      parentDeadlineAt,\n    });\n  } finally {\n    releaseAdmission?.();","sourceCodeStart":3879,"sourceCodeEnd":3915,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/runtime.ts#L3879-L3915","documentation":"After resolving the wallet amount, the runtime calls parentMeter.carve(walletAmount) to reserve the child's budget from the parent's remaining funds. If the carve returns undefined — the parent meter cannot cover the requested amount — cave_subagent_wallet_unavailable is thrown, refusing to start an unfunded subagent. This prevents children from spending budget the parent does not have.","triggerScenarios":"Dispatching a subagent whose runtime.maxCostUsd/maxTokens exceeds the parent BudgetMeter's remaining balance, so carve() cannot reserve the full amount.","commonSituations":"Long-running parent that already consumed most of its budget; maxCostUsd/maxTokens set higher than the parent's total budget; several subagents dispatched in one turn draining the shared wallet before later ones; budget-denominated (USD) parents with aggressive per-child costs.","solutions":["Lower the subagent's maxCostUsd/maxTokens so it fits within the parent's remaining budget","Increase the parent agent's total budget","Dispatch fewer subagents per turn, or sequence them and re-check remaining budget","Check parentMeter remaining balance before dispatch and skip/fallback when insufficient"],"exampleFix":"// before\nruntime: { kind: \"subagent\", maxCostUsd: 5.0 } // parent budget only $1 left\n// after\nruntime: { kind: \"subagent\", maxCostUsd: 0.25 } // fits remaining parent budget","handlingStrategy":"validation","validationCode":"if (parentMeter !== undefined && parentMeter.remaining() < requiredWalletAmount) {\n  // skip dispatch or request a smaller carve\n}","typeGuard":null,"tryCatchPattern":"try {\n  await dispatchSubagent({ task });\n} catch (e) {\n  if (e.message === \"cave_subagent_wallet_unavailable\") {\n    result = await doWorkInlineWithoutBudget();\n  } else throw e;\n}","preventionTips":["Size each subagent's maxCostUsd/maxTokens below a fraction of the parent's total budget","Check parent meter remaining balance before each dispatch","Avoid dispatching many funded subagents in a single turn","Track cumulative carved amounts against the parent budget"],"tags":["subagent","budget","wallet"],"backgroundTag":"insufficient-funds","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"}