{"record":{"id":"966970eb60cf0cd1","repo":"mastra-ai/mastra","slug":"factory-rule-decision-must-be-an-object","errorCode":null,"errorMessage":"Factory rule decision must be an object.","messagePattern":"Factory rule decision must be an object\\.","errorType":"validation","errorClass":"FactoryRuleValidationError","httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/rules/validation.ts","lineNumber":209,"sourceCode":"    if (!isPlainObject(leaf)) throw new FactoryRuleValidationError(`Factory rules.linear.${event} must be an object.`);\n    assertExactKeys(leaf, ['onEvent'], `Factory rules.linear.${event}`);\n    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      );","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/rules/validation.ts#L191-L227","documentation":"validateFactoryRuleDecision requires its argument to be a plain object representing a rule decision (with a `type` field). If value is not a plain object (null, array, string, function, class instance), this error is thrown. It is called from decision(), the public API for emitting decisions from rule handlers.","triggerScenarios":"Calling decision(null), decision(undefined), decision([type, code]), decision('reject'), or passing a Promise/class instance instead of the decision object literal.","commonSituations":"An onEvent handler accidentally returning/awaiting into decision() a non-object (e.g. awaiting a fetch result before wrapping it); a typo passing the wrong variable; destructuring mistakes producing undefined.","solutions":["Pass a decision object literal like { type: 'transition', idempotencyKey, board, stage }","Check the variable passed to decision() is defined and is an object at the call site","Await any promises before constructing the decision object","Log the value with console.log(typeof v, v) right before calling decision()"],"exampleFix":"// before\nreturn decision(result?.decision) // undefined when result is empty\n// after\nif (!result?.decision) return; // or throw a domain error\nreturn decision(result.decision)","handlingStrategy":"type-guard","validationCode":"function assertDecisionInput(v) {\n  if (v === null || typeof v !== 'object' || Array.isArray(v)) {\n    throw new TypeError('decision() requires a plain object with a type field');\n  }\n}","typeGuard":"const isDecisionInput = (v): v is Record<string, unknown> =>\n  typeof v === 'object' && v !== null && !Array.isArray(v);","tryCatchPattern":"try {\n  return decision(value);\n} catch (e) {\n  if (e instanceof FactoryRuleValidationError && e.message === 'Factory rule decision must be an object.') {\n    logger.error('decision() got non-object', { value });\n    return null; // or a reject decision with a safe default\n  }\n  throw e;\n}","preventionTips":["Await async results before constructing decisions","Destructure carefully so undefined doesn't reach decision()","Type handler return values with the library's input types","Log the value at the call site when debugging"],"tags":["validation","factory-rules","type-error"],"backgroundTag":"schema-validation-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}