{"record":{"id":"988a709475ab759e","repo":"affaan-m/ECC","slug":"tmux-session-already-exists-plan-sessionname","errorCode":null,"errorMessage":"tmux session already exists: ${plan.sessionName}","messagePattern":"tmux session already exists: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/tmux-worktree-orchestrator.js","lineNumber":506,"sourceCode":"  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']);\n\n  if (plan.replaceExisting) {\n    cleanupExistingImpl(plan);\n  } else {\n    const hasSession = spawnSyncImpl('tmux', ['has-session', '-t', plan.sessionName], {\n      encoding: 'utf8',\n      stdio: ['ignore', 'pipe', 'pipe']\n    });\n    if (hasSession.status === 0) {\n      throw new Error(`tmux session already exists: ${plan.sessionName}`);\n    }\n  }\n\n  try {\n    materializePlanImpl(plan);\n\n    for (const workerPlan of plan.workerPlans) {\n      runCommandImpl('git', workerPlan.gitArgs, { cwd: plan.repoRoot });\n      createdState.workerPlans.push(workerPlan);\n      overlaySeedPathsImpl({\n        repoRoot: plan.repoRoot,\n        seedPaths: workerPlan.seedPaths,\n        worktreePath: workerPlan.worktreePath\n      });\n    }\n\n    runCommandImpl(\n      'tmux',","sourceCodeStart":488,"sourceCodeEnd":524,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/tmux-worktree-orchestrator.js#L488-L524","documentation":"Thrown by executePlan in the tmux worktree orchestrator when plan.replaceExisting is falsy and `tmux has-session -t <sessionName>` exits 0, proving a tmux session with that name is already live. The orchestrator refuses to clobber an existing session so it does not hijack or duplicate panes the user is actively using. Passing replaceExisting (or killing the session first) is the only way past the guard.","triggerScenarios":"Calling executePlan(plan) a second time with the same plan.sessionName while the first session is still attached/detached-but-alive. Running two orchestrator plans whose generated session names collide (e.g. same repo slug). A previous run crashed without cleanup, leaving an orphaned tmux session.","commonSituations":"Re-running `dmux`/orchestration during iterative development after a partial failure. SSH disconnect left a session running. Two terminals pointed at the same worktree plan. CI runner reused a tmux server across jobs without `tmux kill-server`.","solutions":["Kill the existing session: `tmux kill-session -t <plan.sessionName>` then re-run.","Set plan.replaceExisting = true so executePlan runs cleanupExisting (kills session + stale worktrees/branches) before materializing.","Generate a unique sessionName per run (append a short hash or timestamp) if you intentionally want parallel orchestrations.","Run `tmux ls` to confirm which sessions exist and decide whether the old one is safe to destroy."],"exampleFix":"// before\nconst plan = { sessionName: 'ecc-main', replaceExisting: false, ... };\nexecutePlan(plan);\n\n// after — let the orchestrator reclaim the name\nconst plan = { sessionName: 'ecc-main', replaceExisting: true, ... };\nexecutePlan(plan);\n\n// or clear it manually first\n// shell: tmux kill-session -t ecc-main","handlingStrategy":"validation","validationCode":"// Before calling executePlan, check for an existing session and decide.\nconst { spawnSync } = require('child_process');\nfunction sessionExists(name) {\n  const r = spawnSync('tmux', ['has-session', '-t', name], { stdio: 'ignore' });\n  return r.status === 0;\n}\nfunction safeExecutePlan(plan) {\n  if (!plan.replaceExisting && sessionExists(plan.sessionName)) {\n    throw new Error(`Refusing to run: tmux session '${plan.sessionName}' exists. Kill it or set replaceExisting=true.`);\n  }\n  return executePlan(plan);\n}","typeGuard":"// Narrow a plan so executePlan cannot hit the 'already exists' guard unexpectedly.\n/** @typedef {{ sessionName: string, replaceExisting?: boolean, repoRoot: string, workerPlans: any[], coordinationDir: string }} Plan */\n/**\n * @param {unknown} p\n * @returns {p is Plan & { replaceExisting: true }}\n */\nfunction isReplaceOrFreshPlan(p) {\n  return !!p && typeof p === 'object'\n    && typeof p.sessionName === 'string'\n    && (p.replaceExisting === true || !sessionExistsSafe(p.sessionName));\n}","tryCatchPattern":"try {\n  executePlan(plan);\n} catch (err) {\n  if (/tmux session already exists/.test(err.message)) {\n    if (autoReplace) { executePlan({ ...plan, replaceExisting: true }); }\n    else { console.error(err.message); process.exit(2); }\n  } else throw err;\n}","preventionTips":["Generate a unique sessionName per orchestration run (append a short hash).","Default plan.replaceExisting to true in CI where stale sessions are expected.","Run `tmux kill-session -t <name>` or `tmux kill-server` in teardown hooks.","Before invoking executePlan, log `tmux ls` so collisions are visible in logs."],"tags":["tmux","orchestration","state-conflict","cli"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}