{"record":{"id":"f94292a9744a9dff","repo":"mastra-ai/mastra","slug":"a-rejection-cannot-be-persisted-with-commit-decisi","errorCode":null,"errorMessage":"A rejection cannot be persisted with commit decisions.","messagePattern":"A rejection cannot be persisted with commit decisions\\.","errorType":"validation","errorClass":"FactoryRuleValidationError","httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/rules/validation.ts","lineNumber":366,"sourceCode":"        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":348,"sourceCodeEnd":376,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/rules/validation.ts#L348-L376","documentation":"A batch passed to validateFactoryRuleDecisions is either a pure commit (create/update/link/message/skill/notification decisions) or a single reject — never both. If any validated decision has type 'reject' the whole batch is thrown out, because persisting a rejection alongside commit decisions would make the transaction semantics ambiguous.","triggerScenarios":"A rule returning an array like [{type:'reject',...},{type:'message',...}] from evaluate, ingestToolResult, transition, or the other listed callers — i.e. any mix containing a reject decision with at least one commit decision.","commonSituations":"Rules that conditionally push a reject into a shared decisions array while other branches push commits; aggregating results from multiple sub-checks where one fails with reject while others succeeded.","solutions":["Return either [reject] alone, or only commit decisions — early-return the reject instead of appending it.","Restructure the rule so a failing condition short-circuits to a single reject decision.","Convert the reject into an error/exception path (or a notification decision) if partial commits are intended."],"exampleFix":"// before\nconst out = [commitDecision()];\nif (bad) out.push({ type: 'reject', ... });\nreturn out;\n// after\nif (bad) return [{ type: 'reject', ... }];\nreturn [commitDecision()];","handlingStrategy":"validation","validationCode":"function checkNoRejectMix(decisions) {\n  const hasReject = decisions.some(d => d.type === 'reject');\n  if (hasReject && decisions.length > 1) {\n    throw new Error('reject must be the only decision in a batch');\n  }\n}","typeGuard":"function isPureRejectBatch(ds: Array<{ type: string }>): ds is [{ type: 'reject' }] {\n  return ds.length === 1 && ds[0].type === 'reject';\n}","tryCatchPattern":"try {\n  return validateFactoryRuleDecisions(decisions);\n} catch (e) {\n  if (e instanceof FactoryRuleValidationError && /rejection cannot be persisted/.test(e.message)) {\n    const reject = decisions.find(d => d.type === 'reject');\n    return validateFactoryRuleDecisions(reject ? [reject] : []); // fail the batch outright\n  }\n  throw e;\n}","preventionTips":["Short-circuit: return the reject decision immediately instead of pushing into a shared array.","Separate reject paths from commit paths in rule code structure.","Write a rule unit test asserting reject batches contain exactly one decision."],"tags":["validation","factory-rules","transaction-semantics"],"backgroundTag":"incompatible-decision-batch","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}