Yeachan-Heo/oh-my-codex · error · Error

failed to read tmux pane topology before split: ${beforeTopo

Error message

failed to read tmux pane topology before split: ${beforeTopology.error}

What it means

Before performing a source-authorized split, the code snapshots the pane topology of the source's window (via listPanesResult on the immutable windowId). If that snapshot read fails, the split is aborted because the post-split reconciliation would be unable to distinguish new panes from pre-existing ones.

Source

Thrown at src/team/tmux-session.ts:388

    `${effect} ; display-message -p ${shellQuoteSingle(receipt)}`,
    "display-message -p ''",
  ]);
  if (!result.ok) throw new Error(`tmux source authority transaction failed: ${result.stderr}`);
  if (result.stdout !== receipt) throw new Error('tmux source authority changed before effect');
  return receipt;
}

export function runSourceAuthorizedSplit(
  source: SourcePaneAuthority,
  buildEffect: (receipt: string) => string,
): string {
  // Reconcile against the immutable window ID, not the mutable session:index
  // target: a concurrent renumber between the guarded split and the after-read
  // must never turn an unrelated window's pane into kill authority.
  const windowTarget = source.windowId;
  const beforeTopology = listPanesResult(windowTarget);
  if (beforeTopology.error) {
    throw new Error(`failed to read tmux pane topology before split: ${beforeTopology.error}`);
  }
  const beforePaneIds = new Set(beforeTopology.panes.map((pane) => pane.paneId));
  const receipt = sourceTransactionReceipt();
  const effect = buildEffect(receipt);
  const result = runTmux([
    'if-shell', '-F', '-t', source.paneId, sourceAuthorityPredicate(source),
    bindSplitWindowReceiptFormat(effect, receipt),
    "display-message -p ''",
  ], true);
  if (!result.ok) throw new Error(`tmux source authority transaction failed: ${result.stderr}`);
  const paneId = parseSplitWindowPaneId(result.stdout, receipt);
  if (!paneId) {
    const afterTopology = listPanesResult(windowTarget);
    const newlyObservedPaneIds = afterTopology.error
      ? []
      : afterTopology.panes
        .filter((pane) => !beforePaneIds.has(pane.paneId) && pane.startCommand.includes(receipt))
        .map((pane) => pane.paneId);

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Check the embedded error: window gone → re-create session; transient → retry split from a fresh authority capture
  2. Verify the window still exists: `tmux list-panes -t @<windowId>`
  3. Pin/verify a tmux version compatible with the format strings used
Defensive patterns

Strategy: retry

Validate before calling

const t = listPanesResult(windowId); if (t.error) throw new Error(`window ${windowId} unreadable: ${t.error}`);

Try / catch

catch (e) { if (/topology before split/.test(e.message)) return retryFromFreshCapture(); throw e; }

Prevention

When it happens

Trigger: runSourceAuthorizedSplit (via guardedSplitPaneId or createTeamSession) when `tmux list-panes -t <windowId>` fails: window closed, session killed, server error, or format-string incompatibility with the installed tmux version.

Common situations: The window/session is torn down concurrently with a split; tmux version differences in list-panes format specifiers; server socket flakiness under heavy load.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/cd07eb8222b6bcae. Report an issue: GitHub.