JuliusBrussee/caveman · error · Error
cave_memory_ttl_invalid
Error message
cave_memory_ttl_invalid
What it means
Thrown by memoryTTLMilliseconds() when the TTL string does not match the strict duration grammar ^([1-9][0-9]*)(m|h|d)$ — a positive integer amount with a single unit of m (minutes), h (hours), or d (days). Zero-prefixed, fractional, negative, empty, or suffixed-with-other-unit strings are all rejected before any memory definition is created.
Source
Thrown at packages/agent/src/primitives.ts:251
if (definition.strategy === "verbatim") {
return definition.recovery === "exact_ccr" ? "exact_ccr" : "inline";
}
if (definition.strategy === "json-index") return "compress";
return "page";
}
export interface MemoryDefinition {
readonly kind: "memory";
readonly namespace: string;
readonly provenance: "local" | "project" | "external";
readonly ttl: string;
readonly recallBudget: number;
readonly consent: "local_only" | "project_shared";
}
export function memoryTTLMilliseconds(value: string): number {
const match = /^([1-9][0-9]*)(m|h|d)$/.exec(value);
if (!match) throw new Error("cave_memory_ttl_invalid");
const amount = Number(match[1]);
const scale = match[2] === "m" ? 60_000 : match[2] === "h" ? 3_600_000 : 86_400_000;
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)}`);View on GitHub (pinned to 27d5a3981a)
Solutions
- Use a plain positive integer followed by exactly one of m, h, or d — e.g. '30m', '12h', '7d'
- If the TTL arrives in another unit, convert it first (e.g. Math.ceil(minutes) + 'm') and guard against 0/negative results
- Validate config-sourced TTLs with the same regex ^([1-9][0-9]*)(m|h|d)$ at load time so the failure surfaces in config parsing, not agent construction
Example fix
// before
memory({ namespace: 'notes', ttl: '3600s', recallBudget: 10 });
// after
memory({ namespace: 'notes', ttl: '60m', recallBudget: 10 }); Defensive patterns
Strategy: validation
Validate before calling
const TTL_RE = /^([1-9][0-9]*)(m|h|d)$/;
function isTTLString(v: unknown): v is string {
return typeof v === 'string' && TTL_RE.test(v);
} Type guard
function isMemoryTTL(value: unknown): value is `${number}${'m'|'h'|'d'}` { return typeof value === 'string' && /^([1-9][0-9]*)(m|h|d)$/.test(value); } Try / catch
try { memoryTTLMilliseconds(ttl); } catch (e) { if (e instanceof Error && e.message === 'cave_memory_ttl_invalid') throw new ConfigError(`ttl '${mask(ttl)}' must be like '30m', '12h', or '7d'`, { cause: e }); throw e; } Prevention
- Standardize config TTLs on the m/h/d grammar at the config schema level
- Reject ISO-8601 durations at the loader boundary with a clear message
- Write one shared toCaveTtl(ms: number): string helper and use it everywhere
When it happens
Trigger: Calling memory({ ttl: ... }) or memoryTTLMilliseconds() directly with values like '0m', '1.5h', '30s', '7days', '-1d', '', ' m', or '04h' — anything with a leading zero, a decimal, a non-m/h/d unit, or extra characters.
Common situations: Configuring a memory namespace from user or YAML/JSON config where TTLs are written in ISO-8601 ('P1D'), seconds ('3600s'), or human prose ('1 day'); copy-pasting a TTL from another library's duration format (Go, .NET, or dayjs).
Related errors
- caveman agent: memory ttl must use positive m, h, or d durat
- caveman agent: invalid memory namespace ${JSON.stringify(opt
- caveman agent: memory recallBudget must be a non-negative in
- cave_budget_denomination_ambiguous
- cave_budget_max_invalid
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/09a6292c89c56539.
Report an issue: GitHub.