{"record":{"id":"4843ba60e2b87f3d","repo":"mastra-ai/mastra","slug":"factory-rules-github-event-onevent-must-be-a-fu","errorCode":null,"errorMessage":"Factory rules.github.${event}.onEvent must be a function.","messagePattern":"Factory rules\\.github\\.(.+?)\\.onEvent must be a function\\.","errorType":"validation","errorClass":"FactoryRuleValidationError","httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/rules/validation.ts","lineNumber":184,"sourceCode":"\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 } {\n  return {\n    idempotencyKey: boundedString(value.idempotencyKey, 'Factory decision idempotencyKey', MAX_IDEMPOTENCY_KEY_LENGTH),\n  };","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/rules/validation.ts#L166-L202","documentation":"Thrown by assertFactoryRules when a GitHub event leaf object contains an onEvent key whose value is defined but not a function. onEvent is the event handler hook and must be callable. Validation runs eagerly in prepare/defaultFactoryRules so a bad handler type is rejected at configuration time.","triggerScenarios":"Setting rules.github[event] = { onEvent: 'notAFunction' } or { onEvent: true } or { onEvent: 42 }; passing a thenable/Promise instead of a function; forgetting to spread a handler map so a non-function value lands in onEvent.","commonSituations":"Loading handler names as strings from config intending to resolve them later; a variable holding the handler being undefined due to a bad import (undefined passes since only defined non-functions fail — but a string default from env does not); typo assigning the handler to onEvent via string interpolation.","solutions":["Ensure the onEvent value is an actual function reference: { onEvent: handleIssueCommented }","If handlers are configured by name, resolve the name to a function before calling prepare","Check for accidental string wrapping, e.g. { onEvent: 'handler.ts' } instead of an import","Omit onEvent entirely (or set it to undefined) when no handler is needed instead of a placeholder value"],"exampleFix":"// before\n{ github: { issue_commented: { onEvent: 'handlers/issueCommented' } } }\n// after\nimport { issueCommented } from './handlers';\n{ github: { issue_commented: { onEvent: issueCommented } } }","handlingStrategy":"validation","validationCode":"for (const [event, leaf] of Object.entries(rules.github ?? {})) {\n  const h = leaf?.onEvent;\n  if (h !== undefined && typeof h !== 'function') {\n    throw new TypeError(`rules.github.${event}.onEvent must be a function, got ${typeof h}`);\n  }\n}","typeGuard":"const hasFnOnEvent = (leaf) =>\n  leaf?.onEvent === undefined || typeof leaf.onEvent === 'function';","tryCatchPattern":"try {\n  prepare({ rules });\n} catch (e) {\n  if (e instanceof FactoryRuleValidationError && e.message.includes('.onEvent must be a function')) {\n    console.error('Fix onEvent handler reference:', e.message);\n  } else throw e;\n}","preventionTips":["Import the function itself, not the module namespace","Resolve string handler names to functions before prepare","Type configs with the library's decision/rule input types","Use undefined (or omit the key) for 'no handler'"],"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"}