{"record":{"id":"02f874938c233961","repo":"eyaltoledano/claude-task-master","slug":"invalid-transition-event-type-from-this-curr","errorCode":null,"errorMessage":"Invalid transition: ${event.type} from ${this.currentPhase}","messagePattern":"Invalid transition: (.+?) from (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/tm-core/src/modules/workflow/orchestrators/workflow-orchestrator.ts","lineNumber":139,"sourceCode":"\t\t\tthis.handleRetry();\n\t\t\tawait this.triggerAutoPersist();\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle TDD phase transitions within SUBTASK_LOOP\n\t\tif (this.currentPhase === 'SUBTASK_LOOP') {\n\t\t\tawait this.handleTDDPhaseTransition(event);\n\t\t\tawait this.triggerAutoPersist();\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle main workflow phase transitions\n\t\tconst validTransition = this.transitions.find(\n\t\t\t(t) => t.from === this.currentPhase && t.event === event.type\n\t\t);\n\n\t\tif (!validTransition) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid transition: ${event.type} from ${this.currentPhase}`\n\t\t\t);\n\t\t}\n\n\t\t// Execute transition\n\t\tthis.executeTransition(validTransition, event);\n\t\tawait this.triggerAutoPersist();\n\t}\n\n\t/**\n\t * Handle TDD phase transitions (RED -> GREEN -> COMMIT)\n\t */\n\tprivate async handleTDDPhaseTransition(event: WorkflowEvent): Promise<void> {\n\t\tconst currentTDD = this.context.currentTDDPhase || 'RED';\n\n\t\tswitch (event.type) {\n\t\t\tcase 'RED_PHASE_COMPLETE':\n\t\t\t\tif (currentTDD !== 'RED') {","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/eyaltoledano/claude-task-master/blob/c0c98d367c55296bfe69e65680625b6db437af02/packages/tm-core/src/modules/workflow/orchestrators/workflow-orchestrator.ts#L121-L157","documentation":"The orchestrator validates each event against its transition table, matching (from=currentPhase, event=type). If no transition is registered for the current phase/event pair, transition() throws this error instead of silently ignoring the event — the state machine only allows explicitly declared moves.","triggerScenarios":"Dispatching an event that is not valid for the current phase, e.g. START_WORKFLOW when already initialized, COMPLETE_PHASE out of order, COMMIT in a non-committable phase, or duplicate events already consumed by a prior transition.","commonSituations":"Calling startWorkflow() twice; firing COMPLETE_PHASE twice for one phase; events racing so two callers transition the same orchestrator concurrently; replaying a persisted event log against an already-advanced state.","solutions":["Log this.currentPhase and the event type from the message to see exactly which move is illegal.","Check the orchestrator's phase before dispatching (e.g. only send COMPLETE_PHASE when in an active phase).","Deduplicate/serialize event dispatch — don't fire transition() concurrently from multiple code paths.","If starting fresh, ensure startWorkflow is called only once per orchestrator instance.","Verify the transitions table includes the intended edge if you extended the state machine."],"exampleFix":"// before\nawait orchestrator.transition({ type: 'COMPLETE_PHASE' }); // maybe already done\n// after\nif (orchestrator.currentPhase !== 'COMPLETE') {\n  await orchestrator.transition({ type: 'COMPLETE_PHASE' });\n}","handlingStrategy":"validation","validationCode":"const allowed = orchestrator.transitions\n  .filter((t) => t.from === orchestrator.currentPhase)\n  .map((t) => t.event);\nif (!allowed.includes(event.type)) {\n  throw new SkipDispatchError(`${event.type} illegal from ${orchestrator.currentPhase}`);\n}","typeGuard":"function isLegalTransition(o, event) {\n  return o.transitions.some(\n    (t) => t.from === o.currentPhase && t.event === event.type\n  );\n}","tryCatchPattern":"try {\n  await orchestrator.transition(event);\n} catch (e) {\n  if (e.message.startsWith('Invalid transition:')) {\n    console.warn(`skipped ${event.type}: ${e.message}`);\n    return; // or resync state\n  }\n  throw e;\n}","preventionTips":["Track current phase in the caller and dispatch accordingly","Serialize all transition() calls (avoid concurrent dispatch)","Make startWorkflow idempotent at the call site","Unit-test state machine paths for duplicated/out-of-order events"],"tags":["state-machine","workflow","invalid-transition"],"backgroundTag":"invalid-state-transition","analyzedSha":"c0c98d367c55296bfe69e65680625b6db437af02","analyzedAt":"2026-08-29T02:56:26.071Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}