JuliusBrussee/caveman · error
cave_memory_ttl_invalid
cave_memory_ttl_invalid
Error message
cave_memory_ttl_invalid
What it means
memoryTTLMilliseconds parses a human TTL string (e.g. "30m", "12h", "7d") into milliseconds. This first throw fires when the string does not match the required pattern `^[1-9][0-9]*(m|h|d)$` — i.e. it is malformed, has no unit, uses an unsupported unit (s/w/y), starts with 0, is negative, or has separators/whitespace.
Solutions
- Format the TTL as an integer (no leading zeros) followed by `m`, `h`, or `d`, e.g. "30m", "24h", "14d".
- Convert unsupported units before calling: seconds→minutes ("90s"→"2m"), weeks→days ("2w"→"14d").
- Validate the string with the same regex client-side before passing it in.
- Trim whitespace and strip surrounding quotes from config/env-derived values.
Example fix
// before
memoryTTLMilliseconds(process.env.MEM_TTL ?? "30s");
// after
const ttl = (process.env.MEM_TTL ?? "30m").trim();
if (!/^[1-9][0-9]*(m|h|d)$/.test(ttl)) throw new Error("bad TTL");
memoryTTLMilliseconds(ttl); Defensive patterns
Strategy: validation
Validate before calling
const TTL_RE = /^[1-9][0-9]*(m|h|d)$/;
if (typeof ttl !== "string" || !TTL_RE.test(ttl.trim())) {
throw new Error(`TTL must match Nm|Nh|Nd, got: ${JSON.stringify(ttl)}`);
} Try / catch
try {
const ms = memoryTTLMilliseconds(ttl);
} catch (e) {
if (e instanceof Error && e.message === "cave_memory_ttl_invalid") {
console.error(`TTL '${ttl}' is not <integer><m|h|d> (no leading zeros, no s/w units)`);
} else throw e;
} Prevention
- Centralize TTL formatting in one helper that emits only `Nm|Nh|Nd` strings.
- Restrict config to supported units (m/h/d); convert s/w/y at the config boundary.
- Trim and normalize env/config strings before parsing.
- Test TTL parsing with boundary values ("1m", "1d") in CI.
When it happens
Trigger: Calling `memoryTTLMilliseconds("7 days")`, `memoryTTLMilliseconds("30s")`, `memoryTTLMilliseconds("0d")`, `memoryTTLMilliseconds("007h")`, `memoryTTLMilliseconds("12")` (missing unit), or passing a number/undefined instead of a string.
Common situations: Reading TTL from env/config with units like "s" or "w" that the grammar rejects; localized or spelled-out durations ("1 day"); empty string from an unset config value; copy-pasted values with whitespace or trailing punctuation.
Understand the failure class
Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.
Related errors
- caveman agent: memory ttl must use positive m, h, or d…
- cave_memory_value_invalid
- caveman agent: invalid memory namespace
- caveman agent: memory recallBudget must be a non-negative…
- apiKey, baseURL, and agent are required
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/09a6292c89c56539.
Report an issue: GitHub.
Appendix: 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 3ee70a1026)