mastra-ai/mastra · error · FactoryRuleValidationError
Factory rules.linear.${event} must be an object.
Error message
Factory rules.linear.${event} must be an object. What it means
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.
Source
Thrown at mastracode/factory/src/rules/validation.ts:191
if (leaf.onResult !== undefined && typeof leaf.onResult !== 'function') {
throw new FactoryRuleValidationError(`Factory rules.tools.${toolName}.onResult must be a function.`);
}
}
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.');View on GitHub (pinned to 75dd419e61)
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
Example fix
// before
{ linear: { issue_assigned: (ctx) => {} } }
// after
{ linear: { issue_assigned: { onEvent: (ctx) => {} } } } Defensive patterns
Strategy: validation
Validate before calling
for (const [event, leaf] of Object.entries(rules.linear ?? {})) {
if (leaf === null || typeof leaf !== 'object' || Array.isArray(leaf)) {
throw new TypeError(`rules.linear.${event} must be a plain object`);
}
} Type guard
const isLinearRuleLeaf = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
Try / catch
try {
prepare({ rules });
} catch (e) {
if (e instanceof FactoryRuleValidationError && e.message.startsWith('Factory rules.linear.')) {
console.error('Bad linear rule entry:', e.message);
} else throw e;
} Prevention
- 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
When it happens
Trigger: rules.linear = { issue_assigned: myFn } (function instead of wrapper object), or a string/array/null value under an event key.
Common situations: 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.
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} must be an object.
- Factory rules.linear must be an object.
- Google RBAC roleMapping is required.
- Cookie password must be at least 32 characters. Set OKTA_COO
- heartbeatMs must be a finite number no greater than ${MAX_TI
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/ff77daee17f1ede2.
Report an issue: GitHub.