affaan-m/ECC · error · Error
tmux split-window did not return a pane id for
Error message
tmux split-window did not return a pane id for ${workerPlan.workerName} What it means
executePlan creates one tmux pane per worker via 'tmux split-window -d -P -F #{pane_id}' and relies on tmux echoing the new pane id on stdout. If the command succeeds but returns an empty string, the pane id cannot be targeted by later select-pane/send-keys calls, so it throws for that worker.
Solutions
- Check your tmux version ('tmux -V'); upgrade to a modern tmux (>= 2.x) that reliably supports 'split-window -P -F #{pane_id}'.
- Run the split command manually to see what it prints: tmux split-window -d -P -F '#{pane_id}' -t <session>.
- If you pass a custom runtime.runCommand, verify it returns stdout from spawnSync (encoding: 'utf8') rather than discarding it.
- Retry the run — a transient tmux server failure can produce an empty pane id.
Example fix
// before (old tmux without -P support)
tmux split-window -d -t my-session
tmux list-panes -F '#{pane_id}' -t my-session | tail -1
// after (tmux >= 2.1)
paneId=$(tmux split-window -d -P -F '#{pane_id}' -t my-session) Defensive patterns
Strategy: try-catch
Validate before calling
const tmuxV = spawnSync('tmux', ['-V'], { encoding: 'utf8' }).stdout.trim();
const [ , major ] = tmuxV.match(/tmux (\d+)/) || [];
if (!major || Number(major) < 2) {
throw new Error(`tmux ${tmuxV} lacks reliable split-window -P support; upgrade tmux`);
} Type guard
const hasPaneId = (out) => typeof out === 'string' && /^%\d+$/.test(out.trim());
Try / catch
const paneId = splitResult.stdout.trim();
if (!paneId) {
console.error('tmux returned no pane id; tmux version:', spawnSync('tmux', ['-V'], { encoding: 'utf8' }).stdout.trim());
// fall back: list panes and diff before/after
} Prevention
- Use tmux >= 2.1 where 'split-window -P -F #{pane_id}' is reliable
- Never override runtime.runCommand with a wrapper that drops stdout
- Smoke-test the exact split command manually against your tmux version
- Keep the tmux server alive for the duration of orchestration (no detach-kill races)
When it happens
Trigger: tmux split-window exits 0 but prints nothing — typically a tmux version quirk with -P/-F, output being swallowed (stdio redirection issue in runCommandImpl), or a session that terminated between split and read; also when the spawn wrapper captures stdout but tmux writes the pane id to a different format target.
Common situations: Very old tmux versions without full -P/-F support; a custom runCommandImpl in the runtime override that drops stdout; the tmux server dying mid-run; race where the session closes immediately after split.
Related errors
- failed ` : ''}
- buildOrchestrationPlan requires at least one worker
- Claude Code did not expose a process id
- Codex probe failed
- failed
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/aadf84ed2cd584cc.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/tmux-worktree-orchestrator.js:550
'send-keys',
'-t',
plan.sessionName,
buildSessionBannerCommand(plan.sessionName, plan.coordinationDir),
'C-m'
],
{ cwd: plan.repoRoot }
);
for (const workerPlan of plan.workerPlans) {
const splitResult = runCommandImpl(
'tmux',
['split-window', '-d', '-P', '-F', '#{pane_id}', '-t', plan.sessionName, '-c', workerPlan.worktreePath],
{ cwd: plan.repoRoot }
);
const paneId = splitResult.stdout.trim();
if (!paneId) {
throw new Error(`tmux split-window did not return a pane id for ${workerPlan.workerName}`);
}
runCommandImpl('tmux', ['select-layout', '-t', plan.sessionName, 'tiled'], { cwd: plan.repoRoot });
runCommandImpl('tmux', ['select-pane', '-t', paneId, '-T', workerPlan.workerSlug], {
cwd: plan.repoRoot
});
runCommandImpl(
'tmux',
[
'send-keys',
'-t',
paneId,
`cd ${shellQuote(workerPlan.worktreePath)} && ${workerPlan.launchCommand}`,
'C-m'
],
{ cwd: plan.repoRoot }
);
}View on GitHub (pinned to 8321021c54)