mastra-ai/mastra · error · FactoryRuleValidationError
Factory rule decision type is unsupported.
Error message
Factory rule decision type is unsupported.
What it means
validateFactoryRuleDecision dispatches on the decision's type against the known set of factory commit decision types (message, invoke-skill, link work item, notification, etc.). A decision whose type is not in the switch's known cases falls to the default branch and is rejected, because the dispatcher has no handler for it. This typically means a typo or a decision type from a newer/older schema version.
Source
Thrown at mastracode/factory/src/rules/validation.ts:354
};
}
case 'notify': {
assertExactKeys(value, ['type', 'idempotencyKey', 'title', 'body', 'level'], 'Factory notify decision');
const body = optionalBoundedString(value.body, 'Factory notification body', MAX_MESSAGE_LENGTH);
const level =
value.level === undefined
? undefined
: enumValue(value.level, ['info', 'warning', 'error'] as const, 'Factory notification level');
return {
type,
...commonCommitFields(value),
title: boundedString(value.title, 'Factory notification title', MAX_TITLE_LENGTH),
...(body ? { body } : {}),
...(level ? { level } : {}),
};
}
default:
throw new FactoryRuleValidationError('Factory rule decision type is unsupported.');
}
}
export function validateFactoryRuleDecisions(values: readonly unknown[], causalDepth = 0): FactoryCommitDecision[] {
if (values.length > MAX_JSON_COLLECTION_SIZE) {
throw new FactoryRuleValidationError('Factory rule produced too many decisions.');
}
const decisions: FactoryCommitDecision[] = [];
for (const value of values) {
const decision = validateFactoryRuleDecision(value, causalDepth);
if (decision.type === 'reject') {
throw new FactoryRuleValidationError('A rejection cannot be persisted with commit decisions.');
}
decisions.push(decision);
}
const keys = decisions.map(decision => decision.idempotencyKey);
if (new Set(keys).size !== keys.length) {
throw new FactoryRuleValidationError('Factory decisions require unique idempotency keys.');View on GitHub (pinned to 75dd419e61)
Solutions
- Use one of the exact supported decision type literals defined by the FactoryCommitDecision union.
- Fix casing/typos — the comparison is exact string equality against the switch cases.
- Upgrade or downgrade so the rule's decision types match the factory runtime's schema version.
- Check the discriminated-union type errors in your rule's TypeScript build to see the allowed literals.
Example fix
// before
{ type: 'invokeSkill', skillName: 'deploy' }
// after
{ type: 'invoke-skill', skillName: 'deploy' } // exact literal from FactoryCommitDecision union Defensive patterns
Strategy: type-guard
Validate before calling
const SUPPORTED_TYPES = new Set(['message', 'invoke-skill', 'link', 'notification', 'reject']); // match library union
function checkType(d) {
if (!SUPPORTED_TYPES.has(d.type)) throw new Error(`Unsupported decision type: ${d.type}`);
} Type guard
type DecisionType = 'message' | 'invoke-skill' | 'link' | 'notification';
function isKnownDecisionType(t: string): t is DecisionType {
return ['message', 'invoke-skill', 'link', 'notification'].includes(t);
} Try / catch
try {
return validateFactoryRuleDecisions([decision]);
} catch (e) {
if (e instanceof FactoryRuleValidationError && /type is unsupported/.test(e.message)) {
throw new Error(`Decision type '${decision.type}' not supported by this factory version; allowed: ${DECISION_TYPES.join(', ')}`);
}
throw e;
} Prevention
- Type decisions with the library's discriminated union so bad literals fail at compile time.
- Never build type strings dynamically with template literals.
- Keep rule code on the same schema version as the factory runtime.
When it happens
Trigger: Emitting a decision with type misspelled (e.g. 'notifcation', 'invokeSkill' vs the exact literal), with wrong casing, or with a type introduced in a different version of the schema than the running factory supports.
Common situations: Hand-written rules with a typo in the type literal; rules copied from docs/examples for a different mastracode version; dynamically built type strings (type: `message${suffix}`).
Related errors
- Factory rule version is required.
- ${label} contains an unsupported field.
- Rule metadata is too large.
- ${label} must be an object.
- ${label}.${stage} must be an object.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/7c4bfe87a067d76d.
Report an issue: GitHub.