affaan-m/ECC · error · Error

rollback failed

Error message

rollback failed: ${errors.join('; ')}

What it means

rollbackCreatedResources attempts to undo partial orchestration setup (removing created worktrees, branches, coordination dirs), collecting each cleanup failure into an errors array. If any rollback step failed, it throws once with all errors joined so the user sees the complete cleanup failure picture.

Solutions

  1. Inspect the joined errors in the message to see which cleanup steps failed.
  2. Manually remove the leftover worktrees: 'git worktree list' then 'git worktree remove --force <path>'.
  3. Delete leftover branches: 'git branch -D orchestrator-<session>-<worker>'.
  4. Remove the coordination directory manually if fs removal failed due to permissions (fix perms or rm -rf).

Example fix

// after a failed rollback
git worktree list
git worktree remove --force ../myrepo-my-session-worker1
git branch -D orchestrator-my-session-worker1
Defensive patterns

Strategy: try-catch

Validate before calling

// before orchestrating, ensure no partial state exists
const stale = spawnSync('git', ['worktree', 'list'], { encoding: 'utf8' }).stdout;
if (stale.includes(sessionName)) {
  spawnSync('git', ['worktree', 'prune']);
}

Try / catch

try {
  executePlan(plan);
} catch (err) {
  if (String(err.message).startsWith('rollback failed:')) {
    console.error('Automatic cleanup failed:', err.message);
    console.error('Clean up manually: git worktree remove --force <path>; git branch -D <branch>');
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling rollbackCreatedResources after a failed executePlan when the spawned cleanup commands (e.g. 'git worktree remove', 'git branch -D', fs.rmSync) themselves fail — e.g. worktree is locked, dirty, or already gone; branch is checked out elsewhere.

Common situations: A first failure left the worktree with uncommitted changes so 'git worktree remove' refuses; the branch is checked out in another worktree; filesystem permission issues prevent removing the coordination dir; concurrent orchestrator runs racing on the same resources.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/bef92c22a3aa56ec. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/tmux-worktree-orchestrator.js:478

    } catch (error) {
      errors.push(error.message);
    }

    if (branchExistsImpl(plan.repoRoot, workerPlan.branchName)) {
      try {
        runCommandImpl('git', ['branch', '-D', workerPlan.branchName], { cwd: plan.repoRoot });
      } catch (error) {
        errors.push(error.message);
      }
    }
  }

  if (createdState.removeCoordinationDir && fs.existsSync(plan.coordinationDir)) {
    fs.rmSync(plan.coordinationDir, { force: true, recursive: true });
  }

  if (errors.length > 0) {
    throw new Error(`rollback failed: ${errors.join('; ')}`);
  }
}

function executePlan(plan, runtime = {}) {
  const spawnSyncImpl = runtime.spawnSync || spawnSync;
  const runCommandImpl = runtime.runCommand || runCommand;
  const materializePlanImpl = runtime.materializePlan || materializePlan;
  const overlaySeedPathsImpl = runtime.overlaySeedPaths || overlaySeedPaths;
  const cleanupExistingImpl = runtime.cleanupExisting || cleanupExisting;
  const rollbackCreatedResourcesImpl = runtime.rollbackCreatedResources || rollbackCreatedResources;
  const createdState = {
    workerPlans: [],
    sessionCreated: false,
    removeCoordinationDir: !fs.existsSync(plan.coordinationDir)
  };

  runCommandImpl('git', ['rev-parse', '--is-inside-work-tree'], { cwd: plan.repoRoot });
  runCommandImpl('tmux', ['-V']);

View on GitHub (pinned to 8321021c54)