Skip to content

Fix remote VM session failing with exec: trap: not found before SSH - #740

Merged
sbertix merged 1 commit into
mainfrom
sbertix/gh-737-remote-vm-session-fails-before-ssh-bash
Jul 29, 2026
Merged

Fix remote VM session failing with exec: trap: not found before SSH#740
sbertix merged 1 commit into
mainfrom
sbertix/gh-737-remote-vm-session-fails-before-ssh-bash

Conversation

@sbertix

@sbertix sbertix commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Closes #737

Summary

Opening a remote VM session over SSH failed before SSH even started, with bash: line 0: exec: trap: not found, whenever local zmx was unavailable (unbundled or over budget).

On macOS, Ghostty runs a surface .shell command string v as /usr/bin/login -flp <user> /bin/bash --noprofile --norc -c "exec -l <v>", so v must begin with an executable. ZmxAttach.buildRemoteCommand returned the bare SSHReconnectLoop.script(...) in the no-local-zmx fallback, and that script opens with the trap shell builtin. Prefixed with Ghostty's exec -l, it became exec -l trap 'exit 130' INT; ..., so exec tried to run trap as a program and the surface died with exit 127 before ssh ran. The zmx-wrapped path was unaffected because it already leads with the quoted zmx executable path.

The fallback now wraps the loop as /bin/sh -c '<loop>' (no leading exec, which would break the same way), so Ghostty produces exec -l /bin/sh -c '<loop>', leading with a real executable and running the loop in a fresh shell. This mirrors the inner /bin/sh -c the zmx-wrapped path already uses; that path is unchanged.

Type of change

  • Bug fix (the linked issue is a bug report)
  • Feature (the linked issue is a feature request marked ready)
  • Documentation
  • Other (please describe)

How was this tested?

Reproduced the failure and verified the fix at the shell level (exec -l trap ... exits 127; the /bin/sh -c-wrapped form exits 0). Added bareReconnectLoopSurvivesGhosttyExecLoginWrapping, which parses the real fallback with sh -n, runs the exact bash -c "exec -l …" shape on a benign wrapped loop, and pins the regression with a negative control on the unwrapped loop. Updated the existing fallback assertion to expect the wrapping.

  • make check passes (format + lint)
  • make test passes
  • I built and ran the app to confirm the change works

Checklist

  • This pull request is linked to an issue with Closes # above.
  • For a feature, the linked issue is labeled ready.
  • I am the author of this work and accountable for it; no commit is authored or co-authored by an AI agent.
  • I have read the Contributing guide and the Code of Conduct.

…table

Ghostty runs a surface command as `bash -c "exec -l <command>"`, so the
command must begin with an executable. When local zmx is unavailable,
buildRemoteCommand returned the bare reconnect loop, which opens with a
`trap` builtin; `exec -l trap ...` then tried to run `trap` as a program
and the remote SSH surface died with `exec: trap: not found` before ssh
started. Wrap the fallback loop in `/bin/sh -c`, mirroring the inner shell
the zmx-wrapped path already uses.
@sbertix
sbertix enabled auto-merge (squash) July 29, 2026 22:41
@sbertix
sbertix merged commit 3ec6fb8 into main Jul 29, 2026
3 checks passed
@sbertix
sbertix deleted the sbertix/gh-737-remote-vm-session-fails-before-ssh-bash branch July 29, 2026 22:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remote VM session fails before SSH: bash exec tries to run trap

1 participant