mastra-ai/mastra · error

[QueueHealthStorage] thresholdsSeconds must be a non-empty a

Error message

[QueueHealthStorage] thresholdsSeconds must be a non-empty array of finite numbers.

What it means

assertValidThresholds validates QueueHealthConfig.thresholdsSeconds at the write boundary. It throws this error when the value is not an array, is empty, or contains any element that is not a finite number (NaN/Infinity included). Descending or duplicate thresholds have their own message.

Source

Thrown at mastracode/factory/src/storage/domains/queue-health/base.ts:35

export interface QueueHealthConfig {
  /** Ordered-ascending age boundaries in seconds, e.g. `[14400, 86400, 259200]`. */
  thresholdsSeconds: number[];
}

/** Default: green <4h, amber <24h, orange <72h, red 72h+. */
export const DEFAULT_QUEUE_HEALTH_CONFIG: QueueHealthConfig = {
  thresholdsSeconds: [14400, 86400, 259200],
};

/**
 * Throw unless `thresholdsSeconds` is a non-empty ascending number list. A
 * descending config would silently invert bucket semantics, so validate at the
 * write boundary rather than trusting callers.
 */
export function assertValidThresholds(config: QueueHealthConfig): void {
  const t = config.thresholdsSeconds;
  if (!Array.isArray(t) || t.length === 0 || t.some(v => typeof v !== 'number' || !Number.isFinite(v))) {
    throw new Error('[QueueHealthStorage] thresholdsSeconds must be a non-empty array of finite numbers.');
  }
  for (let i = 1; i < t.length; i++) {
    if (t[i]! <= t[i - 1]!) {
      throw new Error('[QueueHealthStorage] thresholdsSeconds must be strictly ascending.');
    }
  }
}

/** Validate untrusted JSON into a `QueueHealthConfig`, or `null` when invalid. */
export function parseQueueHealthConfig(body: unknown): QueueHealthConfig | null {
  if (typeof body !== 'object' || body === null) return null;
  const config = body as { thresholdsSeconds?: unknown };
  if (!Array.isArray(config.thresholdsSeconds)) return null;
  try {
    assertValidThresholds(config as QueueHealthConfig);
  } catch {
    return null;
  }

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Provide a non-empty array of finite numbers for thresholdsSeconds
  2. Replace Infinity/NaN sentinels with concrete numeric bounds
  3. Guard the config file parsing so missing/empty thresholds are rejected before save
  4. Use parseQueueHealthConfig to validate untrusted JSON before persisting

Example fix

// before
await storage.saveConfig({ thresholdsSeconds: [60, Infinity] });
// after
await storage.saveConfig({ thresholdsSeconds: [60, 300, 900] });
Defensive patterns

Strategy: validation

Validate before calling

function isValidThresholds(t: unknown): t is number[] {
  return Array.isArray(t) && t.length > 0 && t.every(v => typeof v === 'number' && Number.isFinite(v));
}
if (!isValidThresholds(config.thresholdsSeconds)) throw new Error('thresholdsSeconds must be a non-empty finite number array');

Type guard

function isQueueHealthConfig(body: unknown): body is QueueHealthConfig {
  const t = (body as QueueHealthConfig | undefined)?.thresholdsSeconds;
  return isValidThresholds(t);
}

Try / catch

try {
  await storage.saveConfig(config);
} catch (e) {
  if (e instanceof Error && e.message.includes('non-empty array of finite numbers')) {
    throw new BadRequest('thresholdsSeconds is required as a non-empty list of finite numbers');
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling saveConfig (or parseQueueHealthConfig) with thresholdsSeconds = [], undefined, a non-array, or an array containing NaN/Infinity/strings/nulls.

Common situations: Config loaded from a JSON file where the key was missing or the array was emptied by a filter; UI submitting an un-filled thresholds list; Infinity used as a sentinel upper bound.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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