JuliusBrussee/caveman · error
cave_subagent_unpriced_budget
cave_subagent_unpriced_budget
Error message
cave_subagent_unpriced_budget
What it means
Before a model call made under subagent SpendLedgers, the runtime computes the worst-case USD ceiling for the call via catalogSearchCeiling(provider/model, contextWindow, outputTokens) (catalog.ts:229). If the catalog has no price row for that model, the ceiling is undefined: a budgeted subagent cannot reserve against a model the catalog cannot price. Every ledger is marked incomplete (markSpendIncomplete) and the call throws before any provider traffic.
Source
Thrown at packages/agent/src/runtime.ts:4666
function reserveProviderSpend(
ledgers: readonly SpendLedger[],
model: Model<Api>,
requestedOutputTokens: number | undefined,
): SpendReservation[] {
if (ledgers.length === 0) return [];
const outputTokens = Math.min(
model.maxTokens,
requestedOutputTokens ?? model.maxTokens,
);
const ceilingUsd = catalogSearchCeiling(
`${model.provider}/${model.id}`,
model.contextWindow,
outputTokens,
);
if (ceilingUsd === undefined) {
markSpendIncomplete(ledgers);
throw new Error("cave_subagent_unpriced_budget");
}
for (const ledger of ledgers) {
if (ledger.incomplete) throw new Error("cave_subagent_spend_evidence_incomplete");
if (ledger.actualUsd + ledger.reservedUsd + ceilingUsd > ledger.limitUsd) {
throw new Error(ledger.exceededCode);
}
}
const reservations = ledgers.map((ledger) => ({
ledger,
ceilingUsd,
provider: model.provider,
model: model.id,
}));
for (const { ledger } of reservations) ledger.reservedUsd += ceilingUsd;
return reservations;
}
function settleProviderSpend(View on GitHub (pinned to 766dce6b13)
Solutions
- Point the subagent (and everything it can call) at a model the catalog prices
- Remove maxCostUsd from the run if unpriced models are required
- Upgrade/regenerate so catalog.ts carries a region:global row for the model
- Start a fresh run after fixing: the ledgers were just marked incomplete and stay poisoned
Example fix
// before
const child = parent.subagent({ model: 'custom/preview-model', ... }); // parent run has maxCostUsd
// after
const child = parent.subagent({ model: 'anthropic/claude-sonnet-4-5', ... }); Defensive patterns
Strategy: validation
Validate before calling
// Verify every model a budgeted subagent can resolve is priced before the run
import { modelIsPriced } from '@caveman-ai/agent/src/budget.js';
function assertPricedGraph(models: Array<{ provider: string; id: string }>, costCapUsd: number | undefined) {
if (costCapUsd === undefined) return;
const unpriced = models.filter((m) => !modelIsPriced(m.provider, m.id));
if (unpriced.length > 0) {
throw new Error(`remove the cost cap or use priced models: ${unpriced.map((m) => m.provider + '/' + m.id).join(', ')}`);
}
} Try / catch
try {
return await dispatchSubagent(task);
} catch (error) {
if (error instanceof Error && error.message === 'cave_subagent_unpriced_budget') {
// ledgers now marked incomplete: abort the run; switching models requires a fresh run
abortRun();
}
throw error;
} Prevention
- Check modelIsPriced for every model in the subagent graph before starting a maxCostUsd run
- Avoid 'auto' model resolution in budgeted subagents - the resolved model may be unpriced
- Upgrade the package when adding new models so the generated catalog includes them
- Treat unpriced-budget as run-fatal: ledgers are poisoned for the rest of the run
When it happens
Trigger: A subagent tool under maxCostUsd whose definition (or auto-resolved model) is absent from the generated catalog; regional-only price rows that catalog.ts omits by design; catalog drift after a provider update without regenerating; custom model ids in child definitions while the parent carries the cap.
Common situations: Hand-added models in child agents under a parent's maxCostUsd; pinning an old catalog version while providers renamed model ids; unpriced beta/preview models routed into budgeted subagents.
Related errors
- cave_budget_denomination_unavailable
- cave_provider_usage_unpriced
- caveman agent: subagent maxCostUsd must be positive
- caveman agent: subagent maxTokens must be a positive integer
- cave_subagent_wallet_unavailable
AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18).
Data as JSON: /api/errors/11a7a1d03a55b7f4.
Report an issue: GitHub.