{"record":{"id":"cb4c7c1e45d64e55","repo":"mastra-ai/mastra","slug":"factory-transition-message-must-be-an-object","errorCode":null,"errorMessage":"Factory transition message must be an object.","messagePattern":"Factory transition message must be an object\\.","errorType":"validation","errorClass":"FactoryRuleValidationError","httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/rules/validation.ts","lineNumber":234,"sourceCode":"      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.');\n      }\n      let message: { text: string; role?: string } | undefined;\n      if (value.message !== undefined) {\n        if (!isPlainObject(value.message)) {\n          throw new FactoryRuleValidationError('Factory transition message must be an object.');\n        }\n        assertExactKeys(value.message, ['text', 'role'], 'Factory transition message');\n        const role =\n          value.message.role === undefined\n            ? undefined\n            : boundedString(value.message.role, 'Factory transition message role', MAX_ROLE_LENGTH, IDENTIFIER_RE);\n        message = {\n          text: boundedString(value.message.text, 'Factory transition message text', MAX_MESSAGE_LENGTH),\n          ...(role ? { role } : {}),\n        };\n      }\n      return {\n        type,\n        ...commonCommitFields(value),\n        board: enumValue(value.board, FACTORY_RULE_BOARDS, 'Factory transition board'),\n        stage: enumValue(value.stage, FACTORY_RULE_STAGES, 'Factory transition stage'),\n        ...(message ? { message } : {}),\n        ...(value.reenter === true ? { reenter: true } : {}),","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/rules/validation.ts#L216-L252","documentation":"For a 'transition' decision, the optional message field must be a plain object shaped { text, role? }. If message is present but not a plain object, this error is thrown. The message is later attached to the transition and validated further (exact keys, bounded text/role).","triggerScenarios":"decision({ type: 'transition', ..., message: 'hello' }) (string), message: ['hello'], message: new Message(...) (class instance), or message: null where null counts as defined-but-not-object.","commonSituations":"Passing a template string instead of { text: ... }; framework message objects (e.g. from another SDK) passed through unchanged; null from optional chaining where undefined was meant.","solutions":["Wrap text: message: { text: 'Stage updated' } optionally with role: { text, role: 'system' }","Omit the message key entirely instead of passing null","Convert SDK/framework message objects into the plain { text, role? } shape before calling decision()","Pre-check with isPlainObject-like guard: v && typeof v === 'object' && !Array.isArray(v)"],"exampleFix":"// before\ndecision({ type: 'transition', ..., message: `Moved to ${stage}` })\n// after\ndecision({ type: 'transition', ..., message: { text: `Moved to ${stage}` } })","handlingStrategy":"validation","validationCode":"function assertTransitionMessage(d) {\n  const m = (d as any)?.message;\n  if (m !== undefined && (m === null || typeof m !== 'object' || Array.isArray(m))) {\n    throw new TypeError('transition decision message must be { text, role? }');\n  }\n}","typeGuard":"const isTransitionMessage = (v): v is { text: string; role?: string } =>\n  typeof v === 'object' && v !== null && !Array.isArray(v) && typeof (v as any).text === 'string';","tryCatchPattern":"try {\n  return decision(d);\n} catch (e) {\n  if (e instanceof FactoryRuleValidationError && e.message === 'Factory transition message must be an object.') {\n    logger.error('Bad transition message shape', { message: d.message });\n    return decision({ ...d, message: typeof d.message === 'string' ? { text: d.message } : undefined });\n  }\n  throw e;\n}","preventionTips":["Always pass message as { text: string, role?: string }","Omit the message key instead of passing null","Convert external SDK message objects to the plain shape first","Validate decisions with a zod schema before calling decision()"],"tags":["validation","factory-rules","type-error"],"backgroundTag":"schema-validation-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}