eyaltoledano/claude-task-master · error

Cannot finalize workflow: working tree has uncommitted chang

Error message

Cannot finalize workflow: working tree has uncommitted changes.
Staged: ${statusSummary.staged}, Modified: ${statusSummary.modified}, Deleted: ${statusSummary.deleted}, Untracked: ${statusSummary.untracked}
Please commit all changes before finalizing the workflow.

What it means

Thrown by WorkflowService.finalizeWorkflow() after checking the git working tree via GitAdapter.getStatusSummary(). Finalization requires a clean tree so the workflow's final commit is unambiguous; any staged, modified, deleted, or untracked files abort the finalization with a detailed breakdown.

Source

Thrown at packages/tm-core/src/modules/workflow/services/workflow.service.ts:518

	 */
	async finalizeWorkflow(): Promise<WorkflowStatus> {
		if (!this.orchestrator) {
			throw new Error('No active workflow. Start or resume a workflow first.');
		}

		const phase = this.orchestrator.getCurrentPhase();
		if (phase !== 'FINALIZE') {
			throw new Error(
				`Cannot finalize workflow in ${phase} phase. Complete all subtasks first.`
			);
		}

		// Check working tree is clean
		const gitAdapter = new GitAdapter(this.projectRoot);
		const statusSummary = await gitAdapter.getStatusSummary();

		if (!statusSummary.isClean) {
			throw new Error(
				`Cannot finalize workflow: working tree has uncommitted changes.\n` +
					`Staged: ${statusSummary.staged}, Modified: ${statusSummary.modified}, ` +
					`Deleted: ${statusSummary.deleted}, Untracked: ${statusSummary.untracked}\n` +
					`Please commit all changes before finalizing the workflow.`
			);
		}

		// Capture task ID before transitioning
		const context = this.orchestrator.getContext();
		const taskId = context.taskId;

		// Transition to COMPLETE
		await this.orchestrator.transition({ type: 'FINALIZE_COMPLETE' });

		// Get final status before cleanup
		const finalStatus = this.getStatus();

		// Mark main task as done (use workflow's tag from context)

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Commit or stash all pending changes: run `git status` to review, then `git add -A && git commit` (or `git stash`).
  2. Add intentional generated files (logs, build output) to .gitignore so the tree reports clean.
  3. Re-run finalizeWorkflow() after the tree is clean.
  4. If the changes belong to the workflow, complete the intended commit step of the workflow instead of finalizing directly.

Example fix

// before
await workflowService.finalizeWorkflow(); // throws: uncommitted changes
// after
import { execSync } from 'node:child_process';
if (execSync('git status --porcelain').toString().trim() === '') {
  await workflowService.finalizeWorkflow();
} else {
  execSync('git add -A && git commit -m "WIP: before workflow finalize"');
  await workflowService.finalizeWorkflow();
}
Defensive patterns

Strategy: validation

Validate before calling

import { execSync } from 'node:child_process';
const dirty = execSync('git status --porcelain', { cwd: projectRoot }).toString().trim();
if (dirty) throw new Error('Commit or stash changes before finalizing workflow:\n' + dirty);

Try / catch

try {
  await workflowService.finalizeWorkflow();
} catch (e) {
  if (e.message.startsWith('Cannot finalize workflow: working tree has uncommitted changes')) {
    // prompt user to commit/stash, then retry
  } else throw e;
}

Prevention

When it happens

Trigger: Calling finalizeWorkflow() while the project root has uncommitted git changes: staged files, modified tracked files, deleted files, or untracked files — i.e. statusSummary.isClean is false.

Common situations: A subtask step wrote files without committing them, the developer made manual edits mid-workflow, generated artifacts/logs are left untracked, or a .gitignore gap leaves tooling output visible to git.

Related errors


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