mastra-ai/mastra · 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" or "1hr".

What it means

When a TTL option is given as a string, parseActivationTTL parses it against a strict duration regex (number + unit like ms/s/m/h). An unrecognized format throws. This ensures durations are well-formed before they are converted to milliseconds.

Source

Thrown at packages/memory/src/processors/observational-memory/observational-memory.ts:194

  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);
  const unit = rawUnit.toLowerCase();

  if (!Number.isFinite(amount) || amount < 0) {
    throw new Error(`${fieldPath} must be a non-negative number of milliseconds or a duration string like "5m".`);
  }

  const multiplier =
    unit === 'ms' || unit === 'msec' || unit === 'msecs' || unit === 'millisecond' || unit === 'milliseconds'
      ? 1
      : unit === 's' || unit === 'sec' || unit === 'secs' || unit === 'second' || unit === 'seconds'
        ? 1_000

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Use supported forms: "90", "500ms", "5s", "5m", "30min", "2hr", "1h"
  2. Trim the string and strip surrounding quotes/whitespace from env vars before passing
  3. Convert unsupported units yourself (e.g. days -> hours or milliseconds)

Example fix

// before
new ObservationalMemory({ model, activateAfterIdle: "PT5M" }) // ISO-8601 unsupported
// after
new ObservationalMemory({ model, activateAfterIdle: "5m" });
Defensive patterns

Strategy: validation

Validate before calling

const DURATION_RE = /^(\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 (typeof ttl === 'string' && !DURATION_RE.test(ttl.trim())) {
  throw new Error(`Unsupported duration string: ${ttl}`);
}

Type guard

function isDurationString(v: unknown): v is string {
  return typeof v === 'string' &&
    /^(\d+(?:\.\d+)?)\s*(ms|msec|msecs|millisecond|milliseconds|s|sec|secs|second|seconds|m|min|mins|minute|minutes|h|hr|hrs|hour|hours)$/i.test(v.trim());
}

Try / catch

try {
  const mem = new ObservationalMemory(config);
} catch (err) {
  if (err instanceof Error && err.message.includes('duration string')) {
    config.activateAfterIdle = '5m';
  } else throw err;
}

Prevention

When it happens

Trigger: Passing a string TTL that doesn't match the pattern: "5min" (min alone is fine, but "5minutes " with trailing text, "every 5 minutes", "5 mts", "1 day", "", or "5m30s" all fail).

Common situations: Copy-pasting human-readable durations from docs or product specs; env-var strings with whitespace/quotes; ISO-8601 durations ("PT5M") which are not supported.

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


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/80e97081495fae41. Report an issue: GitHub.