mastra-ai/mastra · error
Unsupported Factory stage: ${stage}
Error message
Unsupported Factory stage: ${stage} What it means
requireFactoryStage validates that a user-supplied stage string is one of the known FactoryRuleStage values (via isFactoryRuleStage) before a work-item transition mutation is sent. If the stage is not in the allowed union, it throws 'Unsupported Factory stage: <stage>' to prevent invalid board transitions from reaching the server.
Source
Thrown at mastracode/factory-ui/src/hooks/useWorkItems.ts:143
},
onError: (_err, _vars, context) => {
if (context?.previous) queryClient.setQueryData(listKey, context.previous);
},
onSuccess: item => {
patchCards(queryClient, listKey, cards => cards.map(i => (i.id === item.id ? item : i)));
},
});
}
type TransitionWorkItemVariables = {
item: WorkItem;
board: FactoryBoard;
stage: string;
cause?: string;
};
function requireFactoryStage(stage: string): FactoryRuleStage {
if (!isFactoryRuleStage(stage)) throw new Error(`Unsupported Factory stage: ${stage}`);
return stage;
}
export function useTransitionWorkItemMutation(factoryProjectId: string | undefined) {
const { baseUrl } = useApiConfig();
const queryClient = useQueryClient();
const listKey = queryKeys.workItems(factoryProjectId);
const mutationKey = ['factory', 'transition-work-item', factoryProjectId] as const;
const mutation = useMutation({
mutationKey,
mutationFn: ({ item, board, stage, cause = 'board_drag' }: TransitionWorkItemVariables) =>
transitionWorkItem(baseUrl, requireFactoryProjectId(factoryProjectId), item.id, {
board,
stage: requireFactoryStage(stage),
expectedRevision: item.revision,
requestId: crypto.randomUUID(),
cause,
}),View on GitHub (pinned to 75dd419e61)
Solutions
- Print/inspect the exact stage value in the error and compare it to the FactoryRuleStage union; correct the caller to use a valid stage.
- Update the isFactoryRuleStage guard / stage type union if a new legitimate stage was added server-side.
- Constrain the transition UI to a fixed list of valid stages instead of accepting arbitrary strings.
- Add a pre-submit validation mapping unknown stages to their canonical equivalents before calling the mutation.
Example fix
// before
await transition.mutateAsync({ workItemId, stage: column.id }); // column.id may be arbitrary
// after
if (!isFactoryRuleStage(column.id)) {
toast.error(`Column '${column.id}' is not a valid Factory stage`);
return;
}
await transition.mutateAsync({ workItemId, stage: column.id }); Defensive patterns
Strategy: validation
Validate before calling
if (!isFactoryRuleStage(stage)) {
toast.error(`Unsupported stage: ${stage}`);
return;
} Type guard
const FACTORY_STAGES = ['backlog','todo','in_progress','review','done'] as const;
type FactoryRuleStage = typeof FACTORY_STAGES[number];
function isFactoryRuleStage(s: string): s is FactoryRuleStage {
return (FACTORY_STAGES as readonly string[]).includes(s);
} Try / catch
try {
await transition.mutateAsync({ workItemId, stage });
} catch (e) {
if (e instanceof Error && e.message.startsWith('Unsupported Factory stage')) {
toast.error(e.message);
} else throw e;
} Prevention
- Drive stage dropdowns from the same typed constant list used by the guard.
- Never accept raw column ids from external data without validating against the stage union.
- Re-validate persisted stage preferences after upgrades.
When it happens
Trigger: Calling the mutation returned by useTransitionWorkItemMutation with variables.stage set to a string that is not a FactoryRuleStage — e.g. a free-text stage from a dropdown, a renamed stage, a typo like 'in-progres', or a stage from a different board's configuration.
Common situations: Board stages were customized/renamed on the server but the UI's stage union is stale; dragging a card to a column whose id is not a canonical stage; persisted user preferences referencing an old stage name after a version upgrade.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Factory project is required
- Factory runs require one exclusive destination stage
- ${flag} must be one of: ${allowed.join(', ')}
- SCHEDULES_INVALID_SIGNAL_TYPE
- SCHEDULES_INVALID_STATUS
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/2b12f2619d9c1c5d.
Report an issue: GitHub.