fix(client): handle remote terminal hangup (backport #2827) - #5
Open
dhh wants to merge 1 commit into
Open
Conversation
refs herdrdev#2424 (cherry picked from commit b660cad)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cherry-picks upstream herdrdev/herdr#2827 (
b660cad, merged 2026-08-15) ontoomarchy, which is still at0766aa57(2026-08-10) and ships without it.Why
herdr clientaborts withSIGABRTand dumps core when the outer terminal goes away. On one Omarchy machine,coredumpctlhas 15 herdr cores; 8 of them are on the currently packaged build.The packaged build is the problem:
0766aa57does contain the earlier fix for herdrdev#2424 (#2427,ca1af383,let _ = ratatui::try_restore()atsrc/client/mod.rs:609), but it does not containb660cad, sosrc/client/mod.rs:1329is still:Evidence
Every one of the 15 cores has fds 0, 1 and 2 on a deleted PTY — the terminal was already gone when the process wrote to stderr:
The 8 cores on the packaged
r13build all abort at the identical offsetherdr + 0x112a01a, which disassembles to thecallshim into libcabort:/dev/pts/23 (deleted)/dev/pts/21 (deleted)/dev/pts/22 (deleted)/dev/pts/21 (deleted)/dev/pts/20 (deleted)/dev/pts/17 (deleted)/dev/pts/12 (deleted)/dev/pts/13 (deleted)(The other 7 cores are the same failure on older builds, at that build's own abort offset.)
The panic payload recovered from the core is:
which is the
panic!inside std'sprint_to(library/std/src/io/stdio.rs) — i.e. aneprint!-family macro whose write returnedEIO. The binary's fatal messagethread panicked while processing panic. aborting.is reached, and the five-frame Rust panic block atherdr + 0x1108b52appears twice in the crashing stack, which is the double panic.Sequence
ClientError::ConnectionLostwhen the transport ends.eprintln!("herdr: {err}")writes the final diagnostic to a stderr whose PTY master is gone.write()returnsEIO, so the macro panics.SIGABRT, core dumped, and a desktop crash notification each time.What this changes
Straight cherry-pick of
b660cad:restore_terminal_statereturnsio::Result<()>instead of discarding errors.TerminalGuardgains arestoredflag and a consumingrestore(), soDropdoes not restore twice.let _ = writeln!(io::stderr(), "herdr: {err}"), which cannot panic.tests/client_mode.rs.The only conflict was
docs/next/CHANGELOG.md, where upstream's### Fixedsection carries entries for other commits not in this backport. Resolved by keeping only the#2424line.Verification
cargo check --all-targetspasses on this branch (ZIGpointed at zig 0.15.2, matching the PKGBUILD).client_exits_cleanly_when_terminal_hangs_upand neighbours).Not verified here: a runtime reproduction against a rebuilt binary. The reasoning above is from the cores plus the packaged source, not from observing the patched build survive a hangup.
Follow-up
pkgbuilds/herdr/PKGBUILDinomacom-io/omarchy-pkgspins_commit=0766aa57. It needs bumping past this commit before the packaged build picks the fix up.Opened on behalf of @dhh, from cores on his machine. Prepared by Claude Fable 5 via Claude Code.