{"record":{"id":"d239f03c72ae9fb3","repo":"mastra-ai/mastra","slug":"queuehealthstorage-thresholdsseconds-must-be-str","errorCode":null,"errorMessage":"[QueueHealthStorage] thresholdsSeconds must be strictly ascending.","messagePattern":"\\[QueueHealthStorage\\] thresholdsSeconds must be strictly ascending\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/storage/domains/queue-health/base.ts","lineNumber":39,"sourceCode":"\n/** Default: green <4h, amber <24h, orange <72h, red 72h+. */\nexport const DEFAULT_QUEUE_HEALTH_CONFIG: QueueHealthConfig = {\n  thresholdsSeconds: [14400, 86400, 259200],\n};\n\n/**\n * Throw unless `thresholdsSeconds` is a non-empty ascending number list. A\n * descending config would silently invert bucket semantics, so validate at the\n * write boundary rather than trusting callers.\n */\nexport function assertValidThresholds(config: QueueHealthConfig): void {\n  const t = config.thresholdsSeconds;\n  if (!Array.isArray(t) || t.length === 0 || t.some(v => typeof v !== 'number' || !Number.isFinite(v))) {\n    throw new Error('[QueueHealthStorage] thresholdsSeconds must be a non-empty array of finite numbers.');\n  }\n  for (let i = 1; i < t.length; i++) {\n    if (t[i]! <= t[i - 1]!) {\n      throw new Error('[QueueHealthStorage] thresholdsSeconds must be strictly ascending.');\n    }\n  }\n}\n\n/** Validate untrusted JSON into a `QueueHealthConfig`, or `null` when invalid. */\nexport function parseQueueHealthConfig(body: unknown): QueueHealthConfig | null {\n  if (typeof body !== 'object' || body === null) return null;\n  const config = body as { thresholdsSeconds?: unknown };\n  if (!Array.isArray(config.thresholdsSeconds)) return null;\n  try {\n    assertValidThresholds(config as QueueHealthConfig);\n  } catch {\n    return null;\n  }\n  return { thresholdsSeconds: [...(config as QueueHealthConfig).thresholdsSeconds] };\n}\n\n/**","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/storage/domains/queue-health/base.ts#L21-L57","documentation":"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.'","triggerScenarios":"saveConfig or parseQueueHealthConfig called with thresholdsSeconds like [300, 60] (descending) or [60, 60] (duplicate) — the t[i] <= t[i-1] check fires.","commonSituations":"User reordering thresholds in a settings UI without re-sorting; hand-edited config file; merging configs where two entries collide on the same value.","solutions":["Sort the thresholds numerically ascending and deduplicate before saving","Validate UI input to reject equal or decreasing consecutive values","Fix hand-edited config files to be strictly ascending","Round/compare with tolerance only if values are computed floats — but keep strict order"],"exampleFix":"// before\nawait storage.saveConfig({ thresholdsSeconds: [900, 300, 60] });\n// after\nconst thresholds = [...new Set([900, 300, 60])].sort((a, b) => a - b);\nawait storage.saveConfig({ thresholdsSeconds: thresholds });","handlingStrategy":"validation","validationCode":"function isStrictlyAscending(t: number[]): boolean {\n  return t.every((v, i) => i === 0 || v > t[i - 1]!);\n}\nconst sorted = [...new Set(thresholds)].sort((a, b) => a - b);\nif (!isStrictlyAscending(sorted)) throw new Error('thresholds must be strictly ascending');","typeGuard":null,"tryCatchPattern":"try {\n  await storage.saveConfig(config);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('strictly ascending')) {\n    await storage.saveConfig({ ...config, thresholdsSeconds: normalizeThresholds(config.thresholdsSeconds) });\n  } else throw e;\n}","preventionTips":["Always sort + dedupe thresholds before persisting","Enforce ordering in the settings UI as the user edits","Add a schema-level refinement (superRefine/custom validator) for ordering","Test with descending and duplicate inputs"],"tags":["validation","config","ordering","queue-health"],"backgroundTag":"schema-validation-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}