mastra-ai/mastra · error · FactoryRuleValidationError
Factory rule decision must be an object.
Error message
Factory rule decision must be an object.
What it means
validateFactoryRuleDecision requires its argument to be a plain object representing a rule decision (with a `type` field). If value is not a plain object (null, array, string, function, class instance), this error is thrown. It is called from decision(), the public API for emitting decisions from rule handlers.
Source
Thrown at mastracode/factory/src/rules/validation.ts:209
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.');
switch (type) {
case 'reject': {
assertExactKeys(value, ['type', 'code', 'reason'], 'Factory reject decision');
return {
type,
code: enumValue(value.code, REJECTION_CODES, 'Factory rejection code'),
reason: boundedString(value.reason, 'Factory rejection reason', MAX_REASON_LENGTH),
};
}
case 'transition': {
assertExactKeys(
value,
['type', 'idempotencyKey', 'board', 'stage', 'message', 'reenter'],
'Factory transition decision',
);View on GitHub (pinned to 75dd419e61)
Solutions
- Pass a decision object literal like { type: 'transition', idempotencyKey, board, stage }
- Check the variable passed to decision() is defined and is an object at the call site
- Await any promises before constructing the decision object
- Log the value with console.log(typeof v, v) right before calling decision()
Example fix
// before return decision(result?.decision) // undefined when result is empty // after if (!result?.decision) return; // or throw a domain error return decision(result.decision)
Defensive patterns
Strategy: type-guard
Validate before calling
function assertDecisionInput(v) {
if (v === null || typeof v !== 'object' || Array.isArray(v)) {
throw new TypeError('decision() requires a plain object with a type field');
}
} Type guard
const isDecisionInput = (v): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v);
Try / catch
try {
return decision(value);
} catch (e) {
if (e instanceof FactoryRuleValidationError && e.message === 'Factory rule decision must be an object.') {
logger.error('decision() got non-object', { value });
return null; // or a reject decision with a safe default
}
throw e;
} Prevention
- Await async results before constructing decisions
- Destructure carefully so undefined doesn't reach decision()
- Type handler return values with the library's input types
- Log the value at the call site when debugging
When it happens
Trigger: Calling decision(null), decision(undefined), decision([type, code]), decision('reject'), or passing a Promise/class instance instead of the decision object literal.
Common situations: An onEvent handler accidentally returning/awaiting into decision() a non-object (e.g. awaiting a fetch result before wrapping it); a typo passing the wrong variable; destructuring mistakes producing undefined.
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 rules.linear.${event}.onEvent must be a function.
- 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/966970eb60cf0cd1.
Report an issue: GitHub.