{"record":{"id":"bef92c22a3aa56ec","repo":"affaan-m/ECC","slug":"rollback-failed-errors-join","errorCode":null,"errorMessage":"rollback failed: ${errors.join('; ')}","messagePattern":"rollback failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/tmux-worktree-orchestrator.js","lineNumber":478,"sourceCode":"    } catch (error) {\n      errors.push(error.message);\n    }\n\n    if (branchExistsImpl(plan.repoRoot, workerPlan.branchName)) {\n      try {\n        runCommandImpl('git', ['branch', '-D', workerPlan.branchName], { cwd: plan.repoRoot });\n      } catch (error) {\n        errors.push(error.message);\n      }\n    }\n  }\n\n  if (createdState.removeCoordinationDir && fs.existsSync(plan.coordinationDir)) {\n    fs.rmSync(plan.coordinationDir, { force: true, recursive: true });\n  }\n\n  if (errors.length > 0) {\n    throw new Error(`rollback failed: ${errors.join('; ')}`);\n  }\n}\n\nfunction executePlan(plan, runtime = {}) {\n  const spawnSyncImpl = runtime.spawnSync || spawnSync;\n  const runCommandImpl = runtime.runCommand || runCommand;\n  const materializePlanImpl = runtime.materializePlan || materializePlan;\n  const overlaySeedPathsImpl = runtime.overlaySeedPaths || overlaySeedPaths;\n  const cleanupExistingImpl = runtime.cleanupExisting || cleanupExisting;\n  const rollbackCreatedResourcesImpl = runtime.rollbackCreatedResources || rollbackCreatedResources;\n  const createdState = {\n    workerPlans: [],\n    sessionCreated: false,\n    removeCoordinationDir: !fs.existsSync(plan.coordinationDir)\n  };\n\n  runCommandImpl('git', ['rev-parse', '--is-inside-work-tree'], { cwd: plan.repoRoot });\n  runCommandImpl('tmux', ['-V']);","sourceCodeStart":460,"sourceCodeEnd":496,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/tmux-worktree-orchestrator.js#L460-L496","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n// executePlan threw, then rollback threw: rollback failed: fatal: ... ; fatal: ...\n// state is now unknown\n\n// after\nconst orchestrator = require('scripts/lib/tmux-worktree-orchestrator');\n// re-run with replaceExisting to converge\norchestrator.executePlan(\n  orchestrator.buildOrchestrationPlan({ ...config, replaceExisting: true }),\n);\n// pre-clean manually if replaceExisting still struggles:\n//   git worktree prune --expire now\n//   git branch -D $(git branch --list 'orchestrator-*')","handlingStrategy":"try-catch","validationCode":"function convergeOrchestratorState(repoRoot, sessionName, branchGlob) {\n  const { runCommand, commandSucceeds } = require('scripts/lib/tmux-worktree-orchestrator');\n  runCommand('git', ['worktree', 'prune', '--expire', 'now'], { cwd: repoRoot });\n  if (commandSucceeds('tmux', ['has-session', '-t', sessionName])) {\n    runCommand('tmux', ['kill-session', '-t', sessionName]);\n  }\n  runCommand('git', ['branch', '-D', branchGlob], { cwd: repoRoot }).status;\n}\n\n// call before re-running executePlan to avoid rollback failures","typeGuard":"function tmuxSessionExists(name) {\n  return commandSucceeds('tmux', ['has-session', '-t', name]);\n}\n\nfunction gitBranchExists(repoRoot, name) {\n  return commandSucceeds('git', ['show-ref', '--verify', '--quiet', `refs/heads/${name}`], { cwd: repoRoot });\n}","tryCatchPattern":"try {\n  executePlan(plan);\n} catch (error) {\n  if (/rollback failed/.test(error.message)) {\n    // rollback itself failed: surface each underlying error and reconverge manually\n    console.error(error.message);\n    convergeOrchestratorState(plan.repoRoot, plan.sessionName, 'orchestrator-*');\n    return;\n  }\n  throw error;\n}","preventionTips":["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."],"tags":["orchestration","rollback","aggregate-error","git","tmux"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}