mastra-ai/mastra · error

[QueueHealthStorage] thresholdsSeconds must be strictly asce

Error message

[QueueHealthStorage] thresholdsSeconds must be strictly ascending.

What it means

After element-type validation, assertValidThresholds enforces strict ascending order (t[i] must be > t[i-1]). Bucket semantics invert silently with a descending or duplicate config, so the library throws '[QueueHealthStorage] thresholdsSeconds must be strictly ascending.'

Source

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

/** 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;
  }
  return { thresholdsSeconds: [...(config as QueueHealthConfig).thresholdsSeconds] };
}

/**

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Sort the thresholds numerically ascending and deduplicate before saving
  2. Validate UI input to reject equal or decreasing consecutive values
  3. Fix hand-edited config files to be strictly ascending
  4. Round/compare with tolerance only if values are computed floats — but keep strict order

Example fix

// before
await storage.saveConfig({ thresholdsSeconds: [900, 300, 60] });
// after
const thresholds = [...new Set([900, 300, 60])].sort((a, b) => a - b);
await storage.saveConfig({ thresholdsSeconds: thresholds });
Defensive patterns

Strategy: validation

Validate before calling

function isStrictlyAscending(t: number[]): boolean {
  return t.every((v, i) => i === 0 || v > t[i - 1]!);
}
const sorted = [...new Set(thresholds)].sort((a, b) => a - b);
if (!isStrictlyAscending(sorted)) throw new Error('thresholds must be strictly ascending');

Try / catch

try {
  await storage.saveConfig(config);
} catch (e) {
  if (e instanceof Error && e.message.includes('strictly ascending')) {
    await storage.saveConfig({ ...config, thresholdsSeconds: normalizeThresholds(config.thresholdsSeconds) });
  } else throw e;
}

Prevention

When it happens

Trigger: saveConfig or parseQueueHealthConfig called with thresholdsSeconds like [300, 60] (descending) or [60, 60] (duplicate) — the t[i] <= t[i-1] check fires.

Common situations: User reordering thresholds in a settings UI without re-sorting; hand-edited config file; merging configs where two entries collide on the same value.

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/d239f03c72ae9fb3. Report an issue: GitHub.