mastra-ai/mastra · error · FactoryRuleValidationError
Factory rules.linear.${event}.onEvent must be a function.
Error message
Factory rules.linear.${event}.onEvent must be a function. What it means
Thrown by assertFactoryRules when a Linear event leaf has an onEvent key whose value is defined but not a function. The onEvent hook is invoked by the rules engine on the corresponding Linear event, so it must be callable. Validation happens at configuration time via prepare/defaultFactoryRules.
Source
Thrown at mastracode/factory/src/rules/validation.ts:194
}
if (!isPlainObject(rules.github)) throw new FactoryRuleValidationError('Factory rules.github must be an object.');
for (const [event, leaf] of Object.entries(rules.github)) {
enumValue(event, FACTORY_GITHUB_EVENTS, 'Factory GitHub event');
if (!isPlainObject(leaf)) throw new FactoryRuleValidationError(`Factory rules.github.${event} must be an object.`);
assertExactKeys(leaf, ['onEvent'], `Factory rules.github.${event}`);
if (leaf.onEvent !== undefined && typeof leaf.onEvent !== 'function') {
throw new FactoryRuleValidationError(`Factory rules.github.${event}.onEvent must be a function.`);
}
}
if (!isPlainObject(rules.linear)) throw new FactoryRuleValidationError('Factory rules.linear must be an object.');
for (const [event, leaf] of Object.entries(rules.linear)) {
enumValue(event, FACTORY_LINEAR_EVENTS, 'Factory Linear event');
if (!isPlainObject(leaf)) throw new FactoryRuleValidationError(`Factory rules.linear.${event} must be an object.`);
assertExactKeys(leaf, ['onEvent'], `Factory rules.linear.${event}`);
if (leaf.onEvent !== undefined && typeof leaf.onEvent !== 'function') {
throw new FactoryRuleValidationError(`Factory rules.linear.${event}.onEvent must be a function.`);
}
}
}
function commonCommitFields(value: Record<string, unknown>): { idempotencyKey: string } {
return {
idempotencyKey: boundedString(value.idempotencyKey, 'Factory decision idempotencyKey', MAX_IDEMPOTENCY_KEY_LENGTH),
};
}
export function validateFactoryRuleDecision(value: unknown, causalDepth = 0): FactoryRuleDecision {
if (causalDepth > MAX_FACTORY_RULE_CAUSAL_DEPTH) {
throw new FactoryRuleValidationError('Factory rule causal depth exceeded.');
}
if (!isPlainObject(value)) throw new FactoryRuleValidationError('Factory rule decision must be an object.');
const type = value.type;
if (typeof type !== 'string') throw new FactoryRuleValidationError('Factory rule decision type is required.');
View on GitHub (pinned to 75dd419e61)
Solutions
- Make sure onEvent is a real function reference, e.g. { onEvent: handleIssueAssigned }
- If importing, check you imported the function itself, not the module or default export object
- Resolve string handler names to functions before calling prepare
- Use `typeof cfg.linear[event].onEvent === 'function'` as a pre-check
Example fix
// before
import * as handlers from './handlers';
{ linear: { issue_assigned: { onEvent: handlers } } }
// after
import { handleIssueAssigned } from './handlers';
{ linear: { issue_assigned: { onEvent: handleIssueAssigned } } } Defensive patterns
Strategy: validation
Validate before calling
for (const [event, leaf] of Object.entries(rules.linear ?? {})) {
const h = leaf?.onEvent;
if (h !== undefined && typeof h !== 'function') {
throw new TypeError(`rules.linear.${event}.onEvent must be a function, got ${typeof h}`);
}
} Type guard
const hasFnOnEvent = (leaf) => leaf?.onEvent === undefined || typeof leaf.onEvent === 'function';
Try / catch
try {
prepare({ rules });
} catch (e) {
if (e instanceof FactoryRuleValidationError && e.message.includes('linear') && e.message.includes('onEvent')) {
console.error('Linear onEvent must be a function:', e.message);
} else throw e;
} Prevention
- Verify named imports resolve to functions
- Do not pass module objects or constructors as onEvent
- Pre-check typeof before prepare in config-loading code
- Keep handler registry as name -> function map and assert on load
When it happens
Trigger: rules.linear[event] = { onEvent: 123 } or { onEvent: {} } or { onEvent: 'fnName' }; passing a class constructor or bound-but-typed value that is not a function.
Common situations: String-based handler references from external config; a misnamed import resolving to an object/default export; accidentally passing the module namespace object instead of a specific function.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Factory rules.github.${event}.onEvent must be a function.
- Factory rule decision must be an object.
- Factory transition reenter must be a boolean.
- Factory transition message must be an object.
- CursorSDKAgent resumeData.agentId must be a string when prov
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/21a39cd3b0e2faa9.
Report an issue: GitHub.