JuliusBrussee/caveman · error
caveman build: maxSearchCostUsd must be positive
Error message
caveman build: maxSearchCostUsd must be positive
What it means
defineBuild requires maxSearchCostUsd to be strictly positive because it caps the dollar budget of candidate-plan search; zero or negative caps would permit no search or imply refunds. The check runs synchronously before the frozen BuildConfig is returned.
Solutions
- Set maxSearchCostUsd to a positive dollar amount, e.g. 5
- Sanity-check the units: the field is USD, not cents
- Validate computed budgets with Number.isFinite and > 0 before defineBuild
- Replace 0 placeholders with a real cap or omit if optional
Example fix
// before
defineBuild({ entry, evals, maxSearchCostUsd: 0 });
// after
defineBuild({ entry, evals, maxSearchCostUsd: 5 }); Defensive patterns
Strategy: validation
Validate before calling
const c = options.maxSearchCostUsd;
if (!(Number.isFinite(c) && c > 0)) {
throw new Error(`maxSearchCostUsd must be a positive USD amount, got ${c}`);
} Type guard
function isValidCost(v: unknown): v is number {
return typeof v === "number" && Number.isFinite(v) && v > 0;
} Prevention
- Document that the field is USD, not cents
- Replace 0 placeholders with real caps or omit optional fields
- Validate monetary config values at load time
When it happens
Trigger: Passing maxSearchCostUsd <= 0 (0, negative), or NaN (the >0 check fails for NaN), when calling defineBuild.
Common situations: Leaving a placeholder 0 in a config; a currency/units mixup (cents vs dollars) producing a tiny or negative number; a computed budget that underflows to 0 or NaN.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- cave_breaker_retry_requires_budget
- cave_budget_denomination_ambiguous
- cave_budget_initial_invalid
- cave_budget_max_invalid
- ccr max storage bytes must be positive
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/5f5528d7b6f1ed5b.
Report an issue: GitHub.
Appendix: source
Thrown at packages/agent/src/build.ts:53
efficiency: options.efficiency ?? "max",
requiredFixturePassRate: options.requiredFixturePassRate ?? 1,
qualityRetention: options.qualityRetention ?? 0.98,
maxSearchCostUsd: options.maxSearchCostUsd ?? 2,
lock: options.lock ?? "strict",
sandbox: options.sandbox ?? "required",
...(options.allowedModels === undefined ? {} : { allowedModels: [...options.allowedModels] }),
...(options.deniedModels === undefined ? {} : { deniedModels: [...options.deniedModels] }),
...(options.maxP95LatencyMs === undefined ? {} : { maxP95LatencyMs: options.maxP95LatencyMs }),
...(options.forbiddenSafetyClasses === undefined ? {} : { forbiddenSafetyClasses: [...options.forbiddenSafetyClasses] }),
};
if (!(config.requiredFixturePassRate > 0 && config.requiredFixturePassRate <= 1)) {
throw new Error("caveman build: requiredFixturePassRate must be in (0,1]");
}
if (!(config.qualityRetention > 0 && config.qualityRetention <= 1)) {
throw new Error("caveman build: qualityRetention must be in (0,1]");
}
if (!(config.maxSearchCostUsd > 0)) {
throw new Error("caveman build: maxSearchCostUsd must be positive");
}
return Object.freeze(config);
}
export interface CavePlan {
schema_version: 1;
plan_id: string;
model: string;
reasoning: "none" | "minimal" | "low" | "medium" | "high";
segment_routes: Array<{
segment_kind: ContextKind;
segment_id?: string;
transform_id: string;
fallback: "original";
}>;
budgets: {
instructions: number;
tools: number;View on GitHub (pinned to 3ee70a1026)