mastra-ai/mastra · error
${moved.code}: ${moved.reason}
Error message
${moved.code}: ${moved.reason} What it means
After the intake stage, the dispatcher transitions the work item to its destination stage. If that destination transition is rejected by the rules engine (moved.status === 'rejected'), a plain Error '<code>: <reason>' is thrown. Unlike the intake failure, the work item already exists, so nothing is rolled back here.
Source
Thrown at mastracode/factory/src/rules/dispatcher.ts:804
throw new Error(`${initial.code}: ${initial.reason}`);
}
expectedRevision = initial.revision;
}
if (decision.stage === 'intake') return;
const moved = await this.#transitionService.transition({
orgId: record.orgId,
factoryProjectId: record.factoryProjectId,
workItemId: result.item.id,
board,
stage: decision.stage,
expectedRevision,
actor: { type: 'system', id: 'factory-rule-dispatcher' },
ingress: { type: 'rule', identity: `decision:${record.idempotencyKey}:${result.item.id}:destination` },
cause: materializedByDecision ? 'linked_item_materialized' : 'linked_item_reconciled',
causalChain,
});
if (moved.status === 'rejected') throw new Error(`${moved.code}: ${moved.reason}`);
}
async #requireItem(record: FactoryDeferredDecisionRecord) {
if (!record.workItemId) throw new Error('Factory decision is not linked to a work item.');
const item = await this.#storage.get({ orgId: record.orgId, id: record.workItemId });
if (!item) throw new Error('Factory work item not found.');
return item;
}
async #findBinding(
record: FactoryDeferredDecisionRecord,
role?: string,
): Promise<FactoryRunBindingRecord | undefined> {
if (!record.workItemId) throw new Error('Factory decision is not linked to a work item.');
const bindings = await this.#storage.listRunBindings(record.orgId, record.factoryProjectId, record.workItemId);
return bindings
.filter(candidate => candidate.status === 'active' && (role === undefined || candidate.role === role))
.sort((left, right) => {View on GitHub (pinned to 75dd419e61)
Solutions
- Parse '<code>: <reason>' from the message to find the rejected transition.
- Check the destination stage is valid and allowed from the current stage in the active rule version.
- Review rule guards for the destination stage against the item's metadata.
- Roll forward the item manually or adjust rules, then re-dispatch to reconcile.
Example fix
// before: assuming dispatch always completes
await dispatcher.dispatch(record);
// after
const res = await dispatcher.dispatch(record).catch(e => { alertOps(e.message); throw e; }); Defensive patterns
Strategy: try-catch
Validate before calling
if (!allowedTransitions(item.stage).includes(destinationStage)) throw new Error(`stage ${item.stage} -> ${destinationStage} not allowed`); Type guard
function parseRejected(e: unknown): { code: string; reason: string } | null {
const m = /^([^:]+): (.+)$/.exec(e instanceof Error ? e.message : '');
return m ? { code: m[1], reason: m[2] } : null;
} Try / catch
try {
await dispatcher.dispatch(record);
} catch (e) {
const r = parseRejected(e);
if (r) await reconcileItemStage(record, r);
else throw e;
} Prevention
- Assert destination stage is reachable from the item's current stage before dispatch.
- Test rule changes against existing in-flight items before rollout.
- Track rejected transition codes in metrics.
When it happens
Trigger: Dispatching a deferred decision where the materialization succeeded but the destination-stage transition (with cause linked_item_materialized or linked_item_reconciled) is rejected by rule evaluation.
Common situations: Stage ordering changed in the new rule version so the destination stage is unreachable; rule conditions for the destination stage fail; reconciling a linked item whose new state violates stage guards.
Related errors
- ${initial.code}: ${initial.reason}
- Factory decision is not linked to a work item.
- Factory work item not found.
- session_unavailable
- unsupported_provider_item
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/12c9a0062fb89974.
Report an issue: GitHub.