JuliusBrussee/caveman · error · Error
caveman agent: memory recallBudget must be a non-negative in
Error message
caveman agent: memory recallBudget must be a non-negative integer
What it means
Thrown by the memory() builder when options.recallBudget is not a safe non-negative integer. The recall budget bounds how many memories a recall pass may return/consume, so fractional values (0.5), negatives, NaN, Infinity, or numeric strings are all rejected because they cannot bound retrieval deterministically.
Source
Thrown at packages/agent/src/primitives.ts:272
const milliseconds = amount * scale;
if (!Number.isSafeInteger(amount) || !Number.isSafeInteger(milliseconds) || milliseconds <= 0) {
throw new Error("cave_memory_ttl_invalid");
}
return milliseconds;
}
export function memory(options: {
namespace: string;
provenance?: MemoryDefinition["provenance"];
ttl: string;
recallBudget: number;
consent?: MemoryDefinition["consent"];
}): MemoryDefinition {
if (!/^[a-z0-9][a-z0-9_-]{0,95}$/.test(options.namespace)) {
throw new Error(`caveman agent: invalid memory namespace ${JSON.stringify(options.namespace)}`);
}
if (!Number.isSafeInteger(options.recallBudget) || options.recallBudget < 0) {
throw new Error("caveman agent: memory recallBudget must be a non-negative integer");
}
try {
memoryTTLMilliseconds(options.ttl);
} catch {
throw new Error("caveman agent: memory ttl must use positive m, h, or d duration");
}
// Fail closed at CONSTRUCTION, not at tool-call time: the durable
// store implements only local, single-tenant memory. A `project`/`external`
// provenance or a `project_shared` consent is a shared-backend contract this
// package does not provide, so it is refused here rather than burning a model
// turn to discover a config the framework already knew was unsupported.
const provenance = options.provenance ?? "local";
if (provenance !== "local") {
throw new Error("cave_memory_provenance_unsupported: only \"local\" memory is supported");
}
const consent = options.consent ?? "local_only";
if (consent !== "local_only") {
throw new Error("cave_memory_consent_unsupported: only \"local_only\" consent is supported");View on GitHub (pinned to 27d5a3981a)
Solutions
- Pass an integer >= 0, e.g. recallBudget: 10; zero is valid when you want recall disabled
- Coerce and round config-sourced values first: Math.max(0, Math.trunc(Number(raw))) and check Number.isFinite before calling memory()
- If computing the budget from a ratio, apply Math.ceil or Math.round to land on an integer
Example fix
// before (config value came in as string)
memory({ namespace: 'notes', ttl: '7d', recallBudget: Number(raw) }); // raw = '10.5'
// after
memory({ namespace: 'notes', ttl: '7d', recallBudget: Math.max(0, Math.trunc(Number(raw))) }); Defensive patterns
Strategy: validation
Validate before calling
function toRecallBudget(raw: unknown): number {
const n = typeof raw === 'number' ? raw : Number(raw);
if (!Number.isSafeInteger(n) || n < 0) throw new Error(`recallBudget must be a non-negative integer, got ${typeof raw}`);
return n;
} Type guard
function isRecallBudget(value: unknown): value is number { return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0; } Prevention
- Coerce numeric config with Number() and Math.trunc at load time
- Never pass ratios unrounded into recallBudget
- 0 is valid — use it deliberately to disable recall
When it happens
Trigger: Calling memory({ recallBudget: ... }) with 0.5, -1, NaN, Infinity, a value above 2^53-1, or a string like '10' coming from unparsed config.
Common situations: Reading recallBudget from JSON/YAML config or CLI args without Number() conversion (it arrives as a string); dividing a token budget by a per-item estimate and passing the fractional result directly.
Related errors
- cave_compaction_option_invalid
- cave_memory_ttl_invalid
- caveman agent: invalid memory namespace ${JSON.stringify(opt
- caveman agent: memory ttl must use positive m, h, or d durat
- cave_budget_denomination_ambiguous
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/062cd4aef838433f.
Report an issue: GitHub.