{"record":{"id":"796b3f313c2dde12","repo":"mastra-ai/mastra","slug":"factory-rules-github-event-must-be-an-object","errorCode":null,"errorMessage":"Factory rules.github.${event} must be an object.","messagePattern":"Factory rules\\.github\\.(.+?) must be an object\\.","errorType":"validation","errorClass":"FactoryRuleValidationError","httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/rules/validation.ts","lineNumber":181,"sourceCode":"  boundedString(rules.version, 'Factory rule version', MAX_VERSION_LENGTH);\n  validateBoardRules(rules.work, 'Factory rules.work');\n  validateBoardRules(rules.review, 'Factory rules.review');\n\n  if (!isPlainObject(rules.tools)) throw new FactoryRuleValidationError('Factory rules.tools must be an object.');\n  for (const [toolName, leaf] of Object.entries(rules.tools)) {\n    boundedString(toolName, 'Factory tool name', 128, IDENTIFIER_RE);\n    if (!isPlainObject(leaf))\n      throw new FactoryRuleValidationError(`Factory rules.tools.${toolName} must be an object.`);\n    assertExactKeys(leaf, ['onResult'], `Factory rules.tools.${toolName}`);\n    if (leaf.onResult !== undefined && typeof leaf.onResult !== 'function') {\n      throw new FactoryRuleValidationError(`Factory rules.tools.${toolName}.onResult must be a function.`);\n    }\n  }\n\n  if (!isPlainObject(rules.github)) throw new FactoryRuleValidationError('Factory rules.github must be an object.');\n  for (const [event, leaf] of Object.entries(rules.github)) {\n    enumValue(event, FACTORY_GITHUB_EVENTS, 'Factory GitHub event');\n    if (!isPlainObject(leaf)) throw new FactoryRuleValidationError(`Factory rules.github.${event} must be an object.`);\n    assertExactKeys(leaf, ['onEvent'], `Factory rules.github.${event}`);\n    if (leaf.onEvent !== undefined && typeof leaf.onEvent !== 'function') {\n      throw new FactoryRuleValidationError(`Factory rules.github.${event}.onEvent must be a function.`);\n    }\n  }\n\n  if (!isPlainObject(rules.linear)) throw new FactoryRuleValidationError('Factory rules.linear must be an object.');\n  for (const [event, leaf] of Object.entries(rules.linear)) {\n    enumValue(event, FACTORY_LINEAR_EVENTS, 'Factory Linear event');\n    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 } {","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/rules/validation.ts#L163-L199","documentation":"This error is thrown by assertFactoryRules when a per-event entry under rules.github is not a plain object. Each GitHub event key in the factory rules config must map to an object holding at most an `onEvent` handler. The library validates the full rules shape up front so invalid rule configs fail fast at prepare/defaultFactoryRules time instead of silently misbehaving at event time.","triggerScenarios":"Calling prepare(...) or defaultFactoryRules(...) with rules.github containing a value for an event key that is a function, string, number, array, null, or class instance instead of a plain object literal, e.g. rules: { github: { issue_commented: myHandler } }.","commonSituations":"Assigning the onEvent callback directly to the event key instead of nesting it inside an object; passing an array of handlers; JSON round-trips turning functions into strings; reusing a config object where the event key was overwritten by a handler.","solutions":["Nest the handler under onEvent: rules.github[event] = { onEvent: fn }","Check that every value in rules.github is a plain object literal created with { }, not a function or array","Log Object.entries(rules.github) and typeof each value before calling prepare","If config comes from JSON/env, remember functions cannot survive serialization; attach onEvent in code after loading config"],"exampleFix":"// before\nprepare({ rules: { github: { issue_commented: (ctx) => {} } } })\n// after\nprepare({ rules: { github: { issue_commented: { onEvent: (ctx) => {} } } } })","handlingStrategy":"validation","validationCode":"function assertGithubRules(rules) {\n  if (rules?.github) {\n    for (const [event, leaf] of Object.entries(rules.github)) {\n      if (leaf === null || typeof leaf !== 'object' || Array.isArray(leaf)) {\n        throw new TypeError(`rules.github.${event} must be a plain object`);\n      }\n    }\n  }\n}","typeGuard":"const isPlainObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);\nconst isGithubRuleLeaf = (v) => isPlainObject(v);","tryCatchPattern":"try {\n  prepare({ rules });\n} catch (e) {\n  if (e instanceof FactoryRuleValidationError && e.message.includes('rules.github.')) {\n    console.error('Invalid github rule entry:', e.message);\n  } else throw e;\n}","preventionTips":["Always wrap handlers in { onEvent: fn }","Never build github rule values as arrays or functions","Validate config with a zod schema before prepare","Attach function handlers in code, not via serialized JSON config"],"tags":["validation","factory-rules","configuration"],"backgroundTag":"schema-validation-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}