fix(exec): treat remote non-zero exit as command failure, not connection failure - #473
Open
abhtripathi wants to merge 2 commits into
Open
fix(exec): treat remote non-zero exit as command failure, not connection failure#473abhtripathi wants to merge 2 commits into
abhtripathi wants to merge 2 commits into
Conversation
abhtripathi
force-pushed
the
BREV-11814/exec-remote-exit-code
branch
from
September 8, 2026 09:39
bd4e8a7 to
e130310
Compare
drewmalin
reviewed
Sep 10, 2026
Comment on lines
+21
to
+27
| // A remote command exiting non-zero is not a CLI error: pass its exit | ||
| // code through so callers can branch on it, and print nothing extra. | ||
| var remoteErr exec.RemoteExitError | ||
| if stderrors.As(err, &remoteErr) { | ||
| done() | ||
| os.Exit(remoteErr.Code) //nolint:gocritic // manually call done | ||
| } |
Contributor
There was a problem hiding this comment.
Is there a way to isolate the changes only to the exec command itself? I was surprised to see that we needed to change the root command handler.
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.
Problem
brev execchecked only whether the ssh process errored, not its exit code. ssh reserves 255 for its own failures and passes every other code through from the remote command. We treated both the same, so any command exiting non-zero was read as a dead connection and triggered the full recovery path: workspace lookup, org-wide refresh, cloudflared check, SSH probe, and a duplicate re-run of the command.This is what was causing customer app timeouts when scripting
brev execin a loop.Changes
classifySSHErrorbranches on the exit code: 255 stays a connection failure, anything else becomes a typedRemoteExitErrorexecin the bash wrapper so the observed code is ssh's own, not bash'sRemoteExitErrorimmediately, skipping the recovery path entirelyrunAndTrackso both recovery branches handle it explicitly and no longer skip analytics on non-zero exitsflattenMultiInstanceErrso a multi-instance run exits 1 instead of picking an arbitrary instance's code out of the multierrormain.gopropagates the real remote exit code instead of always exiting 1, and skips the Sentry report since a non-zero command isn't a CLI errorTesting
New
pkg/cmd/exec/exec_test.go, 5 tests, all passing. Mutation-checked: reverting the 255 logic makes them fail.TestRemoteExitErrorSurvivesWrappingcovers the recovery path specifically, confirmingerrors.Asmatches throughWrapAndTrace, double-wrap, andmultierror.Manually verified against a live instance: exit codes 0/1/7/127 propagate correctly, multi-instance exits 1, and a genuinely unreachable host still gets the full recovery path (ssh returns 255).