JuliusBrussee/caveman · error
cave_subagent_wallet_unavailable
cave_subagent_wallet_unavailable
Error message
cave_subagent_wallet_unavailable
What it means
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.
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
Example fix
// before
runtime: { kind: "subagent", maxCostUsd: 5.0 } // parent budget only $1 left
// after
runtime: { kind: "subagent", maxCostUsd: 0.25 } // fits remaining parent budget Defensive patterns
Strategy: validation
Validate before calling
if (parentMeter !== undefined && parentMeter.remaining() < requiredWalletAmount) {
// skip dispatch or request a smaller carve
} Try / catch
try {
await dispatchSubagent({ task });
} catch (e) {
if (e.message === "cave_subagent_wallet_unavailable") {
result = await doWorkInlineWithoutBudget();
} else throw e;
} Prevention
- 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
When it happens
Trigger: Dispatching a subagent whose runtime.maxCostUsd/maxTokens exceeds the parent BudgetMeter's remaining balance, so carve() cannot reserve the full amount.
Common situations: 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.
Related errors
- cave_subagent_call_budget
- cave_subagent_cost_budget
- cave_subagent_unpriced_budget
- cave_subagent_wallet_denomination_unavailable
- budget is below CCR storage minimum
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/4135bea9d9548534.
Report an issue: GitHub.
Appendix: source
Thrown at packages/agent/src/runtime.ts:3897
const depthLimit = Math.min(
parentOptions.maxSubagentDepth ?? DEFAULT_SUBAGENT_DEPTH_LIMIT,
ABSOLUTE_SUBAGENT_DEPTH_LIMIT,
);
if (depth + 1 > depthLimit) throw new Error("cave_subagent_depth_limit");
// The wallet is carved here, still synchronously, for the same reason: two
// subagents dispatched in one turn must not both be funded out of the same
// remaining budget.
const walletAmount = parentMeter === undefined
? undefined
: parentMeter.denomination === "usd" ? runtime.maxCostUsd : runtime.maxTokens;
if (parentMeter !== undefined && walletAmount === undefined) {
throw new Error("cave_subagent_wallet_denomination_unavailable");
}
const carve = parentMeter === undefined || walletAmount === undefined
? undefined
: parentMeter.carve(walletAmount);
if (parentMeter !== undefined && carve === undefined) {
throw new Error("cave_subagent_wallet_unavailable");
}
let releaseAdmission: (() => void) | undefined;
try {
releaseAdmission = admitSubagent(executionContext.invocationState);
return await runSubagent({
toolDefinition,
runtime,
task,
signal,
parentOptions,
usage,
executionContext,
depth,
childMeter: carve?.child,
parentDeadlineAt,
});
} finally {
releaseAdmission?.();View on GitHub (pinned to 3ee70a1026)