mastra-ai/mastra · error · Error
${fieldPath} must be a non-negative number of milliseconds o
Error message
${fieldPath} must be a non-negative number of milliseconds or a duration string like "5m". What it means
parseActivationTTL validates TTL options (e.g. activateAfterIdle / bufferActivation TTLs) at construction. A number must be a finite, non-negative millisecond value; anything else (negative, NaN, Infinity) throws. This fails fast on invalid durations instead of producing broken timers.
Source
Thrown at packages/memory/src/processors/observational-memory/observational-memory.ts:183
}
export { didProviderChange } from './model-context';
function parseActivationTTL(
value: number | string | false | undefined,
fieldPath: string,
): number | 'auto' | undefined {
if (value === undefined || value === false) {
return undefined;
}
if (value === 'auto') {
return value;
}
if (typeof value === 'number') {
if (!Number.isFinite(value) || value < 0) {
throw new Error(`${fieldPath} must be a non-negative number of milliseconds or a duration string like "5m".`);
}
return value;
}
const trimmed = value.trim();
const match = trimmed.match(
/^(\d+(?:\.\d+)?)\s*(ms|msec|msecs|millisecond|milliseconds|s|sec|secs|second|seconds|m|min|mins|minute|minutes|h|hr|hrs|hour|hours)$/i,
);
if (!match) {
throw new Error(
`${fieldPath} must be a non-negative number of milliseconds or a duration string like "5m" or "1hr".`,
);
}
const rawAmount = match[1]!;
const rawUnit = match[2]!;
const amount = Number(rawAmount);View on GitHub (pinned to 75dd419e61)
Solutions
- Use a non-negative finite number of milliseconds (e.g. 300000 for 5 minutes)
- Use a duration string like "5m", "30s", or "1hr" instead of raw numbers
- Clamp computed values: Math.max(0, computedMs) and validate Number.isFinite before passing
Example fix
// before
new ObservationalMemory({ model, activateAfterIdle: Date.now() - startTime }) // negative
// after
const ttl = Math.max(0, Date.now() - startTime);
new ObservationalMemory({ model, activateAfterIdle: ttl }); Defensive patterns
Strategy: validation
Validate before calling
function assertTtlMs(v: number, field: string): void {
if (!Number.isFinite(v) || v < 0) {
throw new Error(`${field} must be a non-negative number of milliseconds or a duration string like "5m".`);
}
}
assertTtlMs(config.activateAfterIdle, 'activateAfterIdle'); Type guard
function isValidTtlNumber(v: unknown): v is number {
return typeof v === 'number' && Number.isFinite(v) && v >= 0;
} Try / catch
try {
const mem = new ObservationalMemory(config);
} catch (err) {
if (err instanceof Error && err.message.includes('must be a non-negative number of milliseconds')) {
config.activateAfterIdle = 300000; // sane default: 5m
} else throw err;
} Prevention
- Clamp computed TTLs: Math.max(0, value) and check Number.isFinite
- Guard against undefined in arithmetic (undefined - x = NaN)
- Prefer explicit duration strings ("5m") over computed numbers in configs
- Validate config objects at load time, before constructing ObservationalMemory
When it happens
Trigger: Passing a negative number, NaN, or Infinity as a numeric TTL option (e.g. activateAfterIdle: -1) when constructing ObservationalMemory.
Common situations: Computing TTL from a subtraction that went negative (Date.now() - laterTimestamp); math with undefined producing NaN; imported config where Infinity was used as 'never expire'.
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
- ${fieldPath} must be a non-negative number of milliseconds o
- Cookie password must be at least 32 characters. Set WORKOS_C
- Factory rule version is required.
- ${label} must be an object.
- Factory rules must be an object.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/80fbc79cefed53b7.
Report an issue: GitHub.