{"record":{"id":"9fb0d00e13c90603","repo":"netbirdio/netbird","slug":"execute-command-w","errorCode":null,"errorMessage":"execute command: %w","messagePattern":"execute command: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/cmd/ssh.go","lineNumber":590,"sourceCode":"\t}\n\n\tif err != nil {\n\t\tif errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {\n\t\t\treturn nil\n\t\t}\n\n\t\tvar exitErr *ssh.ExitError\n\t\tif errors.As(err, &exitErr) {\n\t\t\tos.Exit(exitErr.ExitStatus())\n\t\t}\n\n\t\tvar exitMissingErr *ssh.ExitMissingError\n\t\tif errors.As(err, &exitMissingErr) {\n\t\t\tlog.Debugf(\"Remote command exited without exit status: %v\", err)\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"execute command: %w\", err)\n\t}\n\treturn nil\n}\n\n// openSSHTerminal opens an interactive SSH terminal.\nfunc openSSHTerminal(ctx context.Context, c *sshclient.Client) error {\n\tif err := c.OpenTerminal(ctx); err != nil {\n\t\tif errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {\n\t\t\treturn nil\n\t\t}\n\n\t\tvar exitMissingErr *ssh.ExitMissingError\n\t\tif errors.As(err, &exitMissingErr) {\n\t\t\tlog.Debugf(\"Remote terminal exited without exit status: %v\", err)\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"open terminal: %w\", err)","sourceCodeStart":572,"sourceCodeEnd":608,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/ssh.go#L572-L608","documentation":"Returned by executeSSHCommand when the remote command fails for a reason other than the cases already handled: a non-zero remote exit is converted to os.Exit(ExitError.ExitStatus()), a missing exit status (ExitMissingError) is logged and treated as success, and context cancellation/deadline returns nil. Whatever remains — session setup failures, I/O errors on the channel, permission denied opening a session — is wrapped as `execute command: %w`.","triggerScenarios":"`netbird ssh <host> <command...>` (optionally --pty) where the SSH session cannot be opened or the command stream fails mid-run: session channel rejected by the peer, stdin/stdout piping errors, terminal request refused when --pty is set, or the connection dropping during execution without a clean exit status.","commonSituations":"Running commands through a heavily loaded or half-dead peer; requesting a PTY for a non-interactive command on peers that restrict channel requests; piping large output that breaks the channel; commands killed by the remote side without an exit-status message.","solutions":["Re-run the command; if it consistently fails while interactive `netbird ssh <host>` works, compare with and without --pty.","Check peer health with `netbird status -d` and the remote sshd logs for rejected session/channel requests.","Capture stderr of the CLI to see the wrapped cause after `execute command:` — it distinguishes channel I/O errors from protocol errors.","If the command must surface the remote exit code, verify you are on a version where ExitError maps to os.Exit (non-zero exits propagate, this error is for the other failure modes).","For scripted use, add a timeout with --timeout or wrap in timeout(1) so hangs surface as context errors (handled as nil/success) instead of channel errors."],"exampleFix":"# before\nnetbird ssh peer1 -- make build\n# -> execute command: session request failed\n\n# after\nnetbird status -d                       # confirm peer healthy\nnetbird ssh peer1 -- make build         # retry once peer is responsive\n# or drop PTY for non-interactive commands: avoid --pty here","handlingStrategy":"try-catch","validationCode":"// pre-flight the command path before the interactive parts of a script\nif command == \"\" {\n\treturn errors.New(\"no command given; pass it after the host\")\n}\nif port < 1 || port > 65535 {\n\treturn fmt.Errorf(\"bad --port %d\", port)\n}\n// confirm peer is reachable so exec failures are not connectivity noise\nif !peerConnected(host) { return fmt.Errorf(\"peer %s not connected\", host) }","typeGuard":null,"tryCatchPattern":"if err := executeSSHCommand(sshCtx, c, command); err != nil {\n\tvar exitErr *ssh.ExitError\n\tswitch {\n\tcase errors.As(err, &exitErr):\n\t\tos.Exit(exitErr.ExitStatus()) // propagate remote exit code\n\tcase isExitMissing(err):\n\t\treturn nil // remote died without status: treat as done\n\tcase errors.Is(err, context.Canceled), errors.Is(err, context.DeadlineExceeded):\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"execute command: %w\", err) // session/IO failure\n\t}\n}","preventionTips":["Skip --pty for non-interactive commands; PTY requests are the most commonly refused channel type.","Wrap scripted runs in a deadline (timeout(1) or ctx) so hangs resolve as context errors instead of channel errors.","Check `netbird status -d` before batch command execution across many peers.","Design scripts to read the process exit code — non-zero remote exits already propagate via os.Exit; only transport failures reach this error."],"tags":["go","ssh","cli","process-exit","remote-execution"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}