eyaltoledano/claude-task-master · error

Invalid transition: ${event.type} in SUBTASK_LOOP

Error message

Invalid transition: ${event.type} in SUBTASK_LOOP

What it means

While the workflow is in the SUBTASK_LOOP phase, handleTDDPhaseTransition only accepts a fixed set of events: RED_PHASE_COMPLETE, GREEN_PHASE_COMPLETE, COMMIT_COMPLETE, SUBTASK_COMPLETE, and ALL_SUBTASKS_COMPLETE. This default branch throws for any other event.type, protecting the state machine from unknown or phase-mismatched events (e.g. workflow-level events meant for other phases such as start/finalize events).

Source

Thrown at packages/tm-core/src/modules/workflow/orchestrators/workflow-orchestrator.ts:289

					this.emit('tdd:red:started');
					this.emit('subtask:started');
				} else {
					// All subtasks complete, transition to FINALIZE
					await this.transition({ type: 'ALL_SUBTASKS_COMPLETE' });
				}
				break;

			case 'ALL_SUBTASKS_COMPLETE':
				// Transition to FINALIZE phase
				this.emit('phase:exited');
				this.currentPhase = 'FINALIZE';
				this.context.currentTDDPhase = undefined;
				this.emit('phase:entered');
				// Note: Don't auto-transition to COMPLETE - requires explicit finalize call
				break;

			default:
				throw new Error(`Invalid transition: ${event.type} in SUBTASK_LOOP`);
		}
	}

	/**
	 * Execute a state transition
	 */
	private executeTransition(
		transition: StateTransition,
		event: WorkflowEvent
	): void {
		// Check guard condition if present
		if (transition.guard && !transition.guard(this.context)) {
			throw new Error(
				`Guard condition failed for transition to ${transition.to}`
			);
		}

		// Check phase-specific guard if present

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Use one of the valid SUBTASK_LOOP events: RED_PHASE_COMPLETE, GREEN_PHASE_COMPLETE, COMMIT_COMPLETE, SUBTASK_COMPLETE, or ALL_SUBTASKS_COMPLETE.
  2. Check the event type string for typos and exact casing against the WorkflowEvent type definition.
  3. If you need to finalize or move to another workflow phase, use the orchestrator's dedicated API (e.g. the explicit finalize call) instead of transitioning events while in SUBTASK_LOOP.
  4. Update callers if the event was renamed in a newer version of @tm/core.

Example fix

// before
await orchestrator.transition({ type: 'SUBTASK_COMPLETED' }); // typo

// after
await orchestrator.transition({ type: 'SUBTASK_COMPLETE' });
Defensive patterns

Strategy: validation

Validate before calling

const SUBTASK_LOOP_EVENTS = ['RED_PHASE_COMPLETE', 'GREEN_PHASE_COMPLETE', 'COMMIT_COMPLETE', 'SUBTASK_COMPLETE', 'ALL_SUBTASKS_COMPLETE'] as const;
if (!SUBTASK_LOOP_EVENTS.includes(event.type as never)) {
  throw new Error(`Event ${event.type} not allowed while in SUBTASK_LOOP`);
}

Type guard

type SubtaskLoopEvent = 'RED_PHASE_COMPLETE' | 'GREEN_PHASE_COMPLETE' | 'COMMIT_COMPLETE' | 'SUBTASK_COMPLETE' | 'ALL_SUBTASKS_COMPLETE';
function isSubtaskLoopEvent(t: string): t is SubtaskLoopEvent {
  return (['RED_PHASE_COMPLETE', 'GREEN_PHASE_COMPLETE', 'COMMIT_COMPLETE', 'SUBTASK_COMPLETE', 'ALL_SUBTASKS_COMPLETE'] as const).includes(t as SubtaskLoopEvent);
}

Try / catch

try {
  await orchestrator.transition(event);
} catch (e) {
  if (e instanceof Error && e.message.includes('in SUBTASK_LOOP')) {
    // event.type is not valid here — map it to a valid SUBTASK_LOOP event or use the phase-specific API
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling transition({ type: '<anything else>' }) while currentPhase is SUBTASK_LOOP — e.g. START, FINALIZE_COMPLETE, PAUSE, a typo like 'SUBTASK_COMPLETED', or an event belonging to the PLANNING/FINALIZE phases.

Common situations: Typo in the event type string; sending workflow-level control events during the subtask loop; copy-pasted dispatch code from a different phase; a version change renaming or removing an event type so older callers send obsolete names.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29). Data as JSON: /api/errors/3cbdda56ffbc3b26. Report an issue: GitHub.