JuliusBrussee/caveman · error
caveman agent: subagent maxCostUsd must be positive
Error message
caveman agent: subagent maxCostUsd must be positive
What it means
The `subagent()` helper validates `maxCostUsd`, which defaults to 1 and sets the USD spend ceiling for the subagent. It must be a finite number greater than 0; `Number.isFinite` also rejects NaN and Infinity. The library throws at tool-creation time so a misconfigured budget is caught before any agent runs.
Solutions
- Pass a finite positive number, e.g. `subagent({ maxCostUsd: 0.5 })`, or omit it to use the default of 1.
- Parse string config with `Number.parseFloat` and validate `Number.isFinite(v) && v > 0` before calling subagent.
- For unlimited spend, pass a very large finite number instead of Infinity or 0.
Example fix
// before
subagent({ name: "worker", maxCostUsd: process.env.BUDGET })
// after
const maxCostUsd = Number.parseFloat(process.env.BUDGET ?? "1");
if (!Number.isFinite(maxCostUsd) || maxCostUsd <= 0) throw new Error("BUDGET must be a positive number");
subagent({ name: "worker", maxCostUsd }) Defensive patterns
Strategy: validation
Validate before calling
const assertBudget = (v) => {
if (v === undefined) return 1;
const n = typeof v === "string" ? Number.parseFloat(v) : v;
if (!Number.isFinite(n) || n <= 0) throw new TypeError(`maxCostUsd must be positive finite, got ${v}`);
return n;
};
subagent({ name: "worker", maxCostUsd: assertBudget(process.env.BUDGET) }); Type guard
const isPositiveFinite = (v) => typeof v === "number" && Number.isFinite(v) && v > 0;
Try / catch
try {
const t = subagent({ maxCostUsd: opts.budget });
} catch (e) {
if (e.message.includes("maxCostUsd must be positive")) {
throw new Error(`Invalid BUDGET '${opts.budget}': use a positive number of US dollars`, { cause: e });
}
throw e;
} Prevention
- Parse monetary config with Number.parseFloat and validate before passing
- Document that 0/Infinity are invalid; use a large finite number for effectively unlimited
- Keep budgets in a typed config object validated once at startup
- Watch for NaN: any failed string parse becomes NaN, which this check rejects
When it happens
Trigger: Calling `subagent({ maxCostUsd: 0 })`, `subagent({ maxCostUsd: -5 })`, `subagent({ maxCostUsd: Infinity })`, `subagent({ maxCostUsd: NaN })`, or passing a non-numeric config value like `"unlimited"`.
Common situations: Setting maxCostUsd from a string env var without parsing to float; passing 0 intending 'no budget'; typing Infinity as a sentinel for unlimited spend; unit mix-ups (cents vs dollars leading to 0.x intended as 0).
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- caveman agent: subagent maxCalls must be a positive integer
- caveman agent: subagent maxContextTokens must be a positive…
- caveman agent: subagent maxTokens must be a positive integer
- apiKey, baseURL, and agent are required
- ASGI context resolver or request bounds are invalid
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/6f45acbc983b4d23.
Report an issue: GitHub.
Appendix: source
Thrown at packages/agent/src/index.ts:178
* This child's wallet in tokens — the denomination sibling of `maxCostUsd`,
* used by a token-metered run. A token-metered run cannot fund a subagent
* that declares no token wallet.
*/
maxTokens?: number;
maxContextTokens?: number;
}): ToolDefinition {
const maxInputChars = options.maxInputChars ?? 32_768;
if (!Number.isSafeInteger(maxInputChars) || maxInputChars <= 0) {
throw new Error("caveman agent: subagent maxInputChars must be a positive integer");
}
const maxCalls = options.maxCalls ?? 1;
const maxCostUsd = options.maxCostUsd ?? 1;
const maxContextTokens = options.maxContextTokens ?? 128_000;
if (!Number.isSafeInteger(maxCalls) || maxCalls <= 0) {
throw new Error("caveman agent: subagent maxCalls must be a positive integer");
}
if (!Number.isFinite(maxCostUsd) || maxCostUsd <= 0) {
throw new Error("caveman agent: subagent maxCostUsd must be positive");
}
if (options.maxTokens !== undefined &&
(!Number.isSafeInteger(options.maxTokens) || options.maxTokens <= 0)) {
throw new Error("caveman agent: subagent maxTokens must be a positive integer");
}
if (!Number.isSafeInteger(maxContextTokens) || maxContextTokens <= 0) {
throw new Error("caveman agent: subagent maxContextTokens must be a positive integer");
}
return tool({
name: options.name,
description: options.description,
input: schema.object({ task: schema.string() }),
effect: "read",
result: "auto",
...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
runtime: {
kind: "subagent",
definition: options.agent,View on GitHub (pinned to 3ee70a1026)