{"record":{"id":"116436220af3ac34","repo":"mastra-ai/mastra","slug":"factory-rule-decision-type-is-required","errorCode":null,"errorMessage":"Factory rule decision type is required.","messagePattern":"Factory rule decision type is required\\.","errorType":"validation","errorClass":"FactoryRuleValidationError","httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/rules/validation.ts","lineNumber":211,"sourceCode":"    if (leaf.onEvent !== undefined && typeof leaf.onEvent !== 'function') {\n      throw new FactoryRuleValidationError(`Factory rules.linear.${event}.onEvent must be a function.`);\n    }\n  }\n}\n\nfunction commonCommitFields(value: Record<string, unknown>): { idempotencyKey: string } {\n  return {\n    idempotencyKey: boundedString(value.idempotencyKey, 'Factory decision idempotencyKey', MAX_IDEMPOTENCY_KEY_LENGTH),\n  };\n}\n\nexport function validateFactoryRuleDecision(value: unknown, causalDepth = 0): FactoryRuleDecision {\n  if (causalDepth > MAX_FACTORY_RULE_CAUSAL_DEPTH) {\n    throw new FactoryRuleValidationError('Factory rule causal depth exceeded.');\n  }\n  if (!isPlainObject(value)) throw new FactoryRuleValidationError('Factory rule decision must be an object.');\n  const type = value.type;\n  if (typeof type !== 'string') throw new FactoryRuleValidationError('Factory rule decision type is required.');\n\n  switch (type) {\n    case 'reject': {\n      assertExactKeys(value, ['type', 'code', 'reason'], 'Factory reject decision');\n      return {\n        type,\n        code: enumValue(value.code, REJECTION_CODES, 'Factory rejection code'),\n        reason: boundedString(value.reason, 'Factory rejection reason', MAX_REASON_LENGTH),\n      };\n    }\n    case 'transition': {\n      assertExactKeys(\n        value,\n        ['type', 'idempotencyKey', 'board', 'stage', 'message', 'reenter'],\n        'Factory transition decision',\n      );\n      if (value.reenter !== undefined && typeof value.reenter !== 'boolean') {\n        throw new FactoryRuleValidationError('Factory transition reenter must be a boolean.');","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/rules/validation.ts#L193-L229","documentation":"A rule decision object must include a string `type` field that selects the decision kind (e.g. 'reject', 'transition'). If value.type is missing or not a string, this error is thrown. The type drives the switch that validates the rest of the decision shape.","triggerScenarios":"decision({ code: 'deny', reason: 'x' }) with type omitted; type set to null/undefined; building the decision with a spread that drops type; type coming from config as a non-string.","commonSituations":"Constructing decisions dynamically where the type key was conditional and never set; JSON payloads from an external source missing the discriminator field; renaming a variable and dropping the type property.","solutions":["Always include a valid type string: { type: 'reject', code, reason } or { type: 'transition', ... }","Check the switch in validateFactoryRuleDecision for the exact accepted type values ('reject', 'transition', etc.) and use one verbatim","Ensure type is a plain string, not an enum wrapper object from another lib","Add a pre-call assertion: if (typeof d.type !== 'string') throw ..."],"exampleFix":"// before\ndecision({ code: 'BLOCKED', reason: 'policy' })\n// after\ndecision({ type: 'reject', code: 'BLOCKED', reason: 'policy' })","handlingStrategy":"validation","validationCode":"const DECISION_TYPES = ['reject', 'transition']; // see switch in validateFactoryRuleDecision\nfunction assertDecisionType(v) {\n  if (typeof v?.type !== 'string' || !DECISION_TYPES.includes(v.type)) {\n    throw new TypeError(`decision.type must be one of: ${DECISION_TYPES.join(', ')}`);\n  }\n}","typeGuard":"const hasDecisionType = (v): v is { type: string } & Record<string, unknown> =>\n  typeof (v as any)?.type === 'string';","tryCatchPattern":"try {\n  return decision(d);\n} catch (e) {\n  if (e instanceof FactoryRuleValidationError && e.message === 'Factory rule decision type is required.') {\n    logger.error('Decision missing type discriminator', { keys: Object.keys(d ?? {}) });\n    return decision({ type: 'reject', code: 'INVALID_DECISION', reason: 'missing type' });\n  }\n  throw e;\n}","preventionTips":["Always build decisions through a single factory function that sets type","Keep type as a string literal, not an enum object","Spread carefully; spread after setting type so it can't be overwritten with undefined","Add a schema check (zod discriminated union) before calling decision()"],"tags":["validation","factory-rules","missing-field"],"backgroundTag":"missing-required-field","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}