affaan-m/ECC · error
rollback failed: ${errors.join('; ')}
Error message
rollback failed: ${errors.join('; ')} What it means
Thrown by rollbackCreatedResources() at the end of an executePlan rollback after one or more cleanup steps (tmux kill-session, git worktree remove, git worktree prune, git branch -D) failed. The function collects all errors into an array and throws a single aggregate so the caller sees every failure, not just the first. The message is the semicolon-joined list of underlying error.message strings.
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 01e15490f0)
Solutions
- Read each segment of the joined message — they correspond to the underlying git/tmux error strings, which usually tell you the exact ref or path.
- Inspect remaining state: tmux ls, git worktree list, git branch --list 'orchestrator-*', and the .orchestration directory.
- Run cleanupExisting manually (or re-run executePlan with replaceExisting: true) to converge on a clean state.
- If rollback consistently fails on a specific step (e.g. branch -D on a checked-out branch), switch the main worktree off that branch before re-running.
Example fix
// before
// executePlan threw, then rollback threw: rollback failed: fatal: ... ; fatal: ...
// state is now unknown
// after
const orchestrator = require('scripts/lib/tmux-worktree-orchestrator');
// re-run with replaceExisting to converge
orchestrator.executePlan(
orchestrator.buildOrchestrationPlan({ ...config, replaceExisting: true }),
);
// pre-clean manually if replaceExisting still struggles:
// git worktree prune --expire now
// git branch -D $(git branch --list 'orchestrator-*') Defensive patterns
Strategy: try-catch
Validate before calling
function convergeOrchestratorState(repoRoot, sessionName, branchGlob) {
const { runCommand, commandSucceeds } = require('scripts/lib/tmux-worktree-orchestrator');
runCommand('git', ['worktree', 'prune', '--expire', 'now'], { cwd: repoRoot });
if (commandSucceeds('tmux', ['has-session', '-t', sessionName])) {
runCommand('tmux', ['kill-session', '-t', sessionName]);
}
runCommand('git', ['branch', '-D', branchGlob], { cwd: repoRoot }).status;
}
// call before re-running executePlan to avoid rollback failures Type guard
function tmuxSessionExists(name) {
return commandSucceeds('tmux', ['has-session', '-t', name]);
}
function gitBranchExists(repoRoot, name) {
return commandSucceeds('git', ['show-ref', '--verify', '--quiet', `refs/heads/${name}`], { cwd: repoRoot });
} Try / catch
try {
executePlan(plan);
} catch (error) {
if (/rollback failed/.test(error.message)) {
// rollback itself failed: surface each underlying error and reconverge manually
console.error(error.message);
convergeOrchestratorState(plan.repoRoot, plan.sessionName, 'orchestrator-*');
return;
}
throw error;
} Prevention
- After any executePlan failure, inspect tmux ls, git worktree list, and git branch --list 'orchestrator-*' before re-running.
- Prefer replaceExisting: true on retries so cleanupExisting converges the state for you.
- Switch the main worktree off any orchestrator-* branch before branch -D runs (a common cause of rollback failure).
- Treat rollback failures as an invariant violation — the workspace is in an unknown state until you reconverge.
When it happens
Trigger: executePlan fails partway and rollback runs; tmux kill-session fails because the session was never created or was already killed; git worktree remove fails because the worktree was already deleted out-of-band; git branch -D fails because the branch is checked out in the main worktree; multiple workers each contribute a cleanup error.
Common situations: The original executePlan failure left the workspace in a state the rollback did not anticipate (e.g. a worktree directory removed manually but the git metadata still present); a prior cleanup already deleted the session; race with another process touching the same branches; permissions issue on the coordination directory.
Related errors
- ${program} ${args.join(' ')} failed${stderr ? `: ${stderr}`
- launcherCommand must be a non-empty string
- Unknown template variable: ${key}
- buildOrchestrationPlan requires at least one worker
- tmux session already exists: ${plan.sessionName}
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/bef92c22a3aa56ec.
Report an issue: GitHub.