Yeachan-Heo/oh-my-codex · error · Error
pane_session_mismatch
pane_session_mismatch
Error message
pane_session_mismatch:${tmuxPaneId}:${paneSession || "missing"} What it means
The bridge verifies the bound pane actually belongs to the expected tmux session via display-message #{session_name}. If the pane has moved, died and been recycled, or the id now resolves to another session, this mismatch error is thrown naming the pane and actual session.
Source
Thrown at src/mcp/hermes-bridge.ts:219
const rawSession = await readSessionState(cwd);
if (!rawSession || !sessionMatchesRequested(rawSession, sessionId)) return null;
const tmuxSessionName = optionalString(rawSession.tmux_session_name);
const tmuxPaneId = optionalString(rawSession.tmux_pane_id);
if (!tmuxSessionName || !tmuxPaneId) return null;
if (!isTmuxPaneId(tmuxPaneId)) {
throw new Error(`unsupported_session_kind:invalid_tmux_pane_binding:${tmuxSessionName}`);
}
const execTmux = deps.execTmuxFileSync ?? defaultExecTmuxFileSync;
try {
execTmux(["has-session", "-t", tmuxSessionName]);
const instanceId = String(execTmux(["show-options", "-qv", "-t", tmuxSessionName, OMX_INSTANCE_OPTION]) ?? "").trim();
if (instanceId !== rawSession.session_id) {
throw new Error(`tmux_instance_mismatch:${tmuxSessionName}:${instanceId || "missing"}`);
}
const paneSession = String(execTmux(["display-message", "-p", "-t", tmuxPaneId, "#{session_name}"]) ?? "").trim();
if (paneSession !== tmuxSessionName) {
throw new Error(`pane_session_mismatch:${tmuxPaneId}:${paneSession || "missing"}`);
}
for (const argv of buildSendPaneArgvs(tmuxPaneId, prompt, true)) {
execTmux(argv);
}
} catch (error) {
const message = errorMessage(error);
const reason = message.startsWith("tmux_instance_mismatch") || message.startsWith("pane_session_mismatch")
? message
: "tmux_send_failed";
throw new Error(`unsupported_session_kind:tmux_prompt_delivery_failed:${tmuxSessionName}:${tmuxPaneId}:${reason}`);
}
return {
session_id: rawSession.session_id,
tmux_session_name: tmuxSessionName,
target: tmuxPaneId,
transport: "tmux_send_keys",
};
}View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Restart the session to rebind to a live pane
- Prune session state referencing dead panes
- Avoid moving panes between sessions while a bridge binding is active
Defensive patterns
Strategy: fallback
Validate before calling
const paneSession = execSync(`tmux display-message -p -t ${paneId} '#{session_name}'`).toString().trim();
if (paneSession !== expectedSession) { /* rebind */ } Try / catch
catch (e) { if ((e as Error).message.startsWith('pane_session_mismatch')) { /* restart session to obtain fresh pane binding */ } } Prevention
- Don't move/kill panes bound to running sessions
- Recreate sessions rather than rearranging panes
- Check pane liveness before each delivery
When it happens
Trigger: execTmux display-message -p -t <paneId> returns a session name different from tmuxSessionName, or empty ('missing') when the pane no longer exists.
Common situations: Pane was killed or swapped in tmux (join-pane/move-pane), session was renamed, or a stale state file points at a recycled pane id.
Related errors
- unsupported_session_kind
- tmux_instance_mismatch
- ${name} is required
- ${name} must be a string
- ${name} must be non-empty
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/80f38c5d6f785aab.
Report an issue: GitHub.