{"record":{"id":"82d0566008f57a3f","repo":"mastra-ai/mastra","slug":"factory-rule-produced-too-many-decisions","errorCode":null,"errorMessage":"Factory rule produced too many decisions.","messagePattern":"Factory rule produced too many decisions\\.","errorType":"validation","errorClass":"FactoryRuleValidationError","httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/rules/validation.ts","lineNumber":360,"sourceCode":"        value.level === undefined\n          ? undefined\n          : enumValue(value.level, ['info', 'warning', 'error'] as const, 'Factory notification level');\n      return {\n        type,\n        ...commonCommitFields(value),\n        title: boundedString(value.title, 'Factory notification title', MAX_TITLE_LENGTH),\n        ...(body ? { body } : {}),\n        ...(level ? { level } : {}),\n      };\n    }\n    default:\n      throw new FactoryRuleValidationError('Factory rule decision type is unsupported.');\n  }\n}\n\nexport function validateFactoryRuleDecisions(values: readonly unknown[], causalDepth = 0): FactoryCommitDecision[] {\n  if (values.length > MAX_JSON_COLLECTION_SIZE) {\n    throw new FactoryRuleValidationError('Factory rule produced too many decisions.');\n  }\n  const decisions: FactoryCommitDecision[] = [];\n  for (const value of values) {\n    const decision = validateFactoryRuleDecision(value, causalDepth);\n    if (decision.type === 'reject') {\n      throw new FactoryRuleValidationError('A rejection cannot be persisted with commit decisions.');\n    }\n    decisions.push(decision);\n  }\n  const keys = decisions.map(decision => decision.idempotencyKey);\n  if (new Set(keys).size !== keys.length) {\n    throw new FactoryRuleValidationError('Factory decisions require unique idempotency keys.');\n  }\n  return decisions;\n}\n","sourceCodeStart":342,"sourceCodeEnd":376,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/rules/validation.ts#L342-L376","documentation":"validateFactoryRuleDecisions bounds how many decisions a single rule evaluation may return, rejecting arrays longer than MAX_JSON_COLLECTION_SIZE before validating each entry. This protects the factory pipeline from runaway rules flooding the dispatcher (and downstream storage/queues) with unbounded work.","triggerScenarios":"A rule returning more than MAX_JSON_COLLECTION_SIZE decisions from evaluate, #ingestIssue, ingestToolResult, validated, or transition — e.g. fan-out over a large issue list or a loop emitting one decision per item in a huge collection.","commonSituations":"Rules that iterate an entire backlog or a large webhook payload without batching; recursive/expanded rules generating a decision per combination of inputs; a bug causing an unbounded loop to emit decisions.","solutions":["Batch the work: emit decisions for a bounded slice (e.g. first N items) and let subsequent evaluations handle the rest.","Aggregate related items into fewer decisions (e.g. one decision referencing a list in metadata) instead of one per item.","Add an explicit limit/early-return in the rule loop and log when truncating.","If the workload is legitimately huge, run it through multiple rule evaluations keyed by page/cursor."],"exampleFix":"// before\nreturn issues.map(i => makeDecision(i)) // unbounded\n// after\nconst BATCH = 50;\nreturn issues.slice(0, BATCH).map(i => makeDecision(i));","handlingStrategy":"validation","validationCode":"const MAX_JSON_COLLECTION_SIZE = 100; // match library cap\nfunction checkBatch(decisions) {\n  if (decisions.length > MAX_JSON_COLLECTION_SIZE) {\n    throw new Error(`Rule produced ${decisions.length} decisions; cap is ${MAX_JSON_COLLECTION_SIZE}`);\n  }\n}","typeGuard":"null","tryCatchPattern":"try {\n  return validateFactoryRuleDecisions(decisions);\n} catch (e) {\n  if (e instanceof FactoryRuleValidationError && /too many decisions/.test(e.message)) {\n    return chunkAndSchedule(decisions); // persist overflow for later evaluations\n  }\n  throw e;\n}","preventionTips":["Cap fan-out loops in rules and process overflow in later evaluations.","Aggregate related items into fewer decisions where possible.","Add logging/metrics on decision count per evaluation to catch runaway rules early."],"tags":["validation","limit-exceeded","factory-rules"],"backgroundTag":"collection-size-limit-exceeded","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}