{"record":{"id":"12c9a0062fb89974","repo":"mastra-ai/mastra","slug":"moved-code-moved-reason","errorCode":null,"errorMessage":"${moved.code}: ${moved.reason}","messagePattern":"\\$\\{moved\\.code\\}: \\$\\{moved\\.reason\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/rules/dispatcher.ts","lineNumber":804,"sourceCode":"        throw new Error(`${initial.code}: ${initial.reason}`);\n      }\n      expectedRevision = initial.revision;\n    }\n    if (decision.stage === 'intake') return;\n\n    const moved = await this.#transitionService.transition({\n      orgId: record.orgId,\n      factoryProjectId: record.factoryProjectId,\n      workItemId: result.item.id,\n      board,\n      stage: decision.stage,\n      expectedRevision,\n      actor: { type: 'system', id: 'factory-rule-dispatcher' },\n      ingress: { type: 'rule', identity: `decision:${record.idempotencyKey}:${result.item.id}:destination` },\n      cause: materializedByDecision ? 'linked_item_materialized' : 'linked_item_reconciled',\n      causalChain,\n    });\n    if (moved.status === 'rejected') throw new Error(`${moved.code}: ${moved.reason}`);\n  }\n\n  async #requireItem(record: FactoryDeferredDecisionRecord) {\n    if (!record.workItemId) throw new Error('Factory decision is not linked to a work item.');\n    const item = await this.#storage.get({ orgId: record.orgId, id: record.workItemId });\n    if (!item) throw new Error('Factory work item not found.');\n    return item;\n  }\n\n  async #findBinding(\n    record: FactoryDeferredDecisionRecord,\n    role?: string,\n  ): Promise<FactoryRunBindingRecord | undefined> {\n    if (!record.workItemId) throw new Error('Factory decision is not linked to a work item.');\n    const bindings = await this.#storage.listRunBindings(record.orgId, record.factoryProjectId, record.workItemId);\n    return bindings\n      .filter(candidate => candidate.status === 'active' && (role === undefined || candidate.role === role))\n      .sort((left, right) => {","sourceCodeStart":786,"sourceCodeEnd":822,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/rules/dispatcher.ts#L786-L822","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: assuming dispatch always completes\nawait dispatcher.dispatch(record);\n// after\nconst res = await dispatcher.dispatch(record).catch(e => { alertOps(e.message); throw e; });","handlingStrategy":"try-catch","validationCode":"if (!allowedTransitions(item.stage).includes(destinationStage)) throw new Error(`stage ${item.stage} -> ${destinationStage} not allowed`);","typeGuard":"function parseRejected(e: unknown): { code: string; reason: string } | null {\n  const m = /^([^:]+): (.+)$/.exec(e instanceof Error ? e.message : '');\n  return m ? { code: m[1], reason: m[2] } : null;\n}","tryCatchPattern":"try {\n  await dispatcher.dispatch(record);\n} catch (e) {\n  const r = parseRejected(e);\n  if (r) await reconcileItemStage(record, r);\n  else throw e;\n}","preventionTips":["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."],"tags":["rules-engine","stage-transition","dispatch","factory"],"backgroundTag":"rule-rejected","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}