{"record":{"id":"ff77daee17f1ede2","repo":"mastra-ai/mastra","slug":"factory-rules-linear-event-must-be-an-object","errorCode":null,"errorMessage":"Factory rules.linear.${event} must be an object.","messagePattern":"Factory rules\\.linear\\.(.+?) must be an object\\.","errorType":"validation","errorClass":"FactoryRuleValidationError","httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/rules/validation.ts","lineNumber":191,"sourceCode":"    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  };\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.');","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/rules/validation.ts#L173-L209","documentation":"Thrown by assertFactoryRules when an individual event entry under rules.linear is not a plain object. Each Linear event key must map to an object whose only allowed key is onEvent (a function). This is eager validation in prepare/defaultFactoryRules.","triggerScenarios":"rules.linear = { issue_assigned: myFn } (function instead of wrapper object), or a string/array/null value under an event key.","commonSituations":"Same as the github variant: assigning the handler directly to the event key; passing handler arrays; config built programmatically where the wrapper object was skipped.","solutions":["Wrap the handler: rules.linear[event] = { onEvent: fn }","Verify each value under rules.linear is a non-null plain object with typeof v === 'object' && !Array.isArray(v)","Build config with a helper that always produces the { onEvent } shape","Inspect Object.entries(rules.linear) with typeof to find the offending key"],"exampleFix":"// before\n{ linear: { issue_assigned: (ctx) => {} } }\n// after\n{ linear: { issue_assigned: { onEvent: (ctx) => {} } } }","handlingStrategy":"validation","validationCode":"for (const [event, leaf] of Object.entries(rules.linear ?? {})) {\n  if (leaf === null || typeof leaf !== 'object' || Array.isArray(leaf)) {\n    throw new TypeError(`rules.linear.${event} must be a plain object`);\n  }\n}","typeGuard":"const isLinearRuleLeaf = (v) =>\n  typeof v === 'object' && v !== null && !Array.isArray(v);","tryCatchPattern":"try {\n  prepare({ rules });\n} catch (e) {\n  if (e instanceof FactoryRuleValidationError && e.message.startsWith('Factory rules.linear.')) {\n    console.error('Bad linear rule entry:', e.message);\n  } else throw e;\n}","preventionTips":["Wrap each linear handler in { onEvent: fn }","Use a helper to construct rule entries consistently","Check typeof of each leaf before prepare","Keep github/linear rule builders shared so both get the same shape"],"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"}