{"record":{"id":"80fbc79cefed53b7","repo":"mastra-ai/mastra","slug":"fieldpath-must-be-a-non-negative-number-of-mill","errorCode":null,"errorMessage":"${fieldPath} must be a non-negative number of milliseconds or a duration string like \"5m\".","messagePattern":"(.+?) must be a non-negative number of milliseconds or a duration string like \"5m\"\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/memory/src/processors/observational-memory/observational-memory.ts","lineNumber":183,"sourceCode":"}\n\nexport { didProviderChange } from './model-context';\n\nfunction parseActivationTTL(\n  value: number | string | false | undefined,\n  fieldPath: string,\n): number | 'auto' | undefined {\n  if (value === undefined || value === false) {\n    return undefined;\n  }\n\n  if (value === 'auto') {\n    return value;\n  }\n\n  if (typeof value === 'number') {\n    if (!Number.isFinite(value) || value < 0) {\n      throw new Error(`${fieldPath} must be a non-negative number of milliseconds or a duration string like \"5m\".`);\n    }\n    return value;\n  }\n\n  const trimmed = value.trim();\n  const match = trimmed.match(\n    /^(\\d+(?:\\.\\d+)?)\\s*(ms|msec|msecs|millisecond|milliseconds|s|sec|secs|second|seconds|m|min|mins|minute|minutes|h|hr|hrs|hour|hours)$/i,\n  );\n\n  if (!match) {\n    throw new Error(\n      `${fieldPath} must be a non-negative number of milliseconds or a duration string like \"5m\" or \"1hr\".`,\n    );\n  }\n\n  const rawAmount = match[1]!;\n  const rawUnit = match[2]!;\n  const amount = Number(rawAmount);","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/memory/src/processors/observational-memory/observational-memory.ts#L165-L201","documentation":"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.","triggerScenarios":"Passing a negative number, NaN, or Infinity as a numeric TTL option (e.g. activateAfterIdle: -1) when constructing ObservationalMemory.","commonSituations":"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'.","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"],"exampleFix":"// before\nnew ObservationalMemory({ model, activateAfterIdle: Date.now() - startTime }) // negative\n// after\nconst ttl = Math.max(0, Date.now() - startTime);\nnew ObservationalMemory({ model, activateAfterIdle: ttl });","handlingStrategy":"validation","validationCode":"function assertTtlMs(v: number, field: string): void {\n  if (!Number.isFinite(v) || v < 0) {\n    throw new Error(`${field} must be a non-negative number of milliseconds or a duration string like \"5m\".`);\n  }\n}\nassertTtlMs(config.activateAfterIdle, 'activateAfterIdle');","typeGuard":"function isValidTtlNumber(v: unknown): v is number {\n  return typeof v === 'number' && Number.isFinite(v) && v >= 0;\n}","tryCatchPattern":"try {\n  const mem = new ObservationalMemory(config);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('must be a non-negative number of milliseconds')) {\n    config.activateAfterIdle = 300000; // sane default: 5m\n  } else throw err;\n}","preventionTips":["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"],"tags":["config","validation","duration"],"backgroundTag":"invalid-config-value","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}