TmuxAdapter must refuse a missing tmux binary instead of throwing #432

Closed
opened 2026-08-21 16:18:49 +00:00 by mph · 0 comments
Owner

Problem

TmuxAdapter shells out at seven sites and never checks that tmux is on PATH.
When it is not, os.proc(...).call throws
java.io.IOException: Cannot run program "tmux", and os-lib spawns the child
from its own thread, so the trace prints on subprocess-shutdown-hook-monitor
and cannot be caught by the calling thread.

Reachable today: IW_WORKSPACE_BACKEND=tmux — or the default, since tmux is the
default — on a machine without tmux. iw start prints a stack trace instead of
the clean error the command's Either types promise.

HerdrAdapter closed the same exposure in IW-422:

core/adapters/Herdr.scala:205
private lazy val installed: Boolean =
  ProcessAdapter.commandExists(TerminalWorkspaceBackend.Herdr.commandName)

Its scaladoc records why a Try is not sufficient. TmuxAdapter has no
equivalent. It went unnoticed because tmux is nearly always installed when
selected, while herdr can be selected by an environment variable alone.

Why this is not a one-line guard

The seven call sites return four different shapes, and each needs a decision
about what "tmux is missing" means:

Site Returns
sessionExists Boolean
currentSessionName Option[String]
isInsideTmux, isCurrentSession Boolean
createSession, killSession, sendKeys Either[String, Unit]
attachSession, switchSession Either over runStreaming exit code

herdr routes everything through one runHerdr helper, which is why its guard is
a single check. TmuxAdapter has no such helper. Introducing one — and deciding
whether a missing binary makes sessionExists false or an error — is the work.

Acceptance

With tmux absent from PATH, every TerminalWorkspaceOps member on the tmux
backend answers through its error channel and no stack trace reaches the user.
A test drives at least one member with the binary absent.

Origin

Recorded in IW-422's LESSONS.md alongside the herdr fix, which noted "this
affects every adapter, not only herdr". Confirmed during lessons triage: the
herdr guard exists, the tmux one does not. The general rule was promoted to
core/CLAUDE.md and kanon note #178.

## Problem `TmuxAdapter` shells out at seven sites and never checks that `tmux` is on PATH. When it is not, `os.proc(...).call` throws `java.io.IOException: Cannot run program "tmux"`, and os-lib spawns the child from its own thread, so the trace prints on `subprocess-shutdown-hook-monitor` and cannot be caught by the calling thread. Reachable today: `IW_WORKSPACE_BACKEND=tmux` — or the default, since tmux is the default — on a machine without tmux. `iw start` prints a stack trace instead of the clean error the command's `Either` types promise. `HerdrAdapter` closed the same exposure in IW-422: core/adapters/Herdr.scala:205 private lazy val installed: Boolean = ProcessAdapter.commandExists(TerminalWorkspaceBackend.Herdr.commandName) Its scaladoc records why a `Try` is not sufficient. `TmuxAdapter` has no equivalent. It went unnoticed because tmux is nearly always installed when selected, while herdr can be selected by an environment variable alone. ## Why this is not a one-line guard The seven call sites return four different shapes, and each needs a decision about what "tmux is missing" means: | Site | Returns | |---|---| | `sessionExists` | `Boolean` | | `currentSessionName` | `Option[String]` | | `isInsideTmux`, `isCurrentSession` | `Boolean` | | `createSession`, `killSession`, `sendKeys` | `Either[String, Unit]` | | `attachSession`, `switchSession` | `Either` over `runStreaming` exit code | herdr routes everything through one `runHerdr` helper, which is why its guard is a single check. `TmuxAdapter` has no such helper. Introducing one — and deciding whether a missing binary makes `sessionExists` false or an error — is the work. ## Acceptance With `tmux` absent from PATH, every `TerminalWorkspaceOps` member on the tmux backend answers through its error channel and no stack trace reaches the user. A test drives at least one member with the binary absent. ## Origin Recorded in IW-422's LESSONS.md alongside the herdr fix, which noted "this affects every adapter, not only herdr". Confirmed during lessons triage: the herdr guard exists, the tmux one does not. The general rule was promoted to `core/CLAUDE.md` and kanon note #178.
mph closed this issue 2026-08-22 07:54:50 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
iterative-works/iw-cli#432
No description provided.