netbirdio/netbird · error
open terminal: %w
Error message
open terminal: %w
What it means
Returned by openSSHTerminal when c.OpenTerminal fails to start the interactive shell. Context cancellation/deadline and a remote exit without exit status (ExitMissingError) are already treated as success; this error covers everything else — failure to request a session channel, the shell/PTY request being refused, local TTY setup failing, or the channel breaking during the session.
Source
Thrown at client/cmd/ssh.go:608
return fmt.Errorf("execute command: %w", err)
}
return nil
}
// openSSHTerminal opens an interactive SSH terminal.
func openSSHTerminal(ctx context.Context, c *sshclient.Client) error {
if err := c.OpenTerminal(ctx); err != nil {
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
return nil
}
var exitMissingErr *ssh.ExitMissingError
if errors.As(err, &exitMissingErr) {
log.Debugf("Remote terminal exited without exit status: %v", err)
return nil
}
return fmt.Errorf("open terminal: %w", err)
}
return nil
}
// startPortForwarding starts local and remote port forwarding based on command line flags
func startPortForwarding(ctx context.Context, c *sshclient.Client, cmd *cobra.Command) error {
for _, forward := range localForwards {
if err := parseAndStartLocalForward(ctx, c, forward, cmd); err != nil {
return fmt.Errorf("local port forward %s: %w", forward, err)
}
}
for _, forward := range remoteForwards {
if err := parseAndStartRemoteForward(ctx, c, forward, cmd); err != nil {
return fmt.Errorf("remote port forward %s: %w", forward, err)
}
}
View on GitHub (pinned to 93e97f4bf1)
Solutions
- Confirm the peer is reachable (`netbird status -d`) and retry — dropped overlay connections are the most common cause.
- If you do not need interactivity, run a one-shot command instead: `netbird ssh <host> <command>` (executeSSHCommand path) or avoid --tty flags.
- Check that your own terminal is a real TTY (`[ -t 0 ]`) when launching; CI/non-interactive shells should use command mode.
- For peers that cannot allocate PTYs, disable PTY requests per the CLI flags for that invocation.
- If it fails consistently for one peer only, inspect that peer's sshd/agent logs — a refused shell request is remote-side policy, not a client bug.
Example fix
# before netbird ssh peer1 # inside a CI step with no TTY # -> open terminal: open /dev/tty: no such device or address # after netbird ssh peer1 -- uname -a # non-interactive command mode, no TTY needed
Defensive patterns
Strategy: try-catch
Validate before calling
// only attempt interactive mode from a real TTY
if !term.IsTerminal(int(os.Stdin.Fd())) || !term.IsTerminal(int(os.Stdout.Fd())) {
return errors.New("no local TTY: use `netbird ssh <host> -- <command>` instead")
}
if !peerConnected(host) {
return fmt.Errorf("peer %s not connected", host)
} Type guard
func hasInteractiveTTY() bool {
return term.IsTerminal(int(os.Stdin.Fd())) && term.IsTerminal(int(os.Stdout.Fd()))
} Try / catch
if err := openSSHTerminal(sshCtx, c); err != nil {
var exitMissing *ssh.ExitMissingError
switch {
case errors.Is(err, context.Canceled), errors.Is(err, context.DeadlineExceeded):
return nil // user hit Ctrl-C / timeout: normal end of session
case errors.As(err, &exitMissing):
return nil // remote closed without status
default:
return fmt.Errorf("open terminal: %w", err)
}
} Prevention
- Detect TTY availability at script start and fall back to command mode instead of failing terminal setup.
- Keep interactive sessions alive with input or enable keepalives so NAT idle timeouts do not kill the channel mid-shell.
- Retry once on a clean reconnect if the overlay dropped; persistent failure for one peer means remote-side PTY/shell policy — check the peer.
- Do not run `netbird ssh <host>` (interactive form) from cron/CI; use the command form.
When it happens
Trigger: `netbird ssh <host>` (no remote command) where the peer refuses the shell or pty-req channel request, the local terminal cannot be put into raw mode, or the overlay connection drops mid-session. Also when the peer's embedded SSH server cannot allocate a PTY (restricted environment, netstack-mode peers without terminal support).
Common situations: First interactive logins to headless peers that reject PTY allocation; running `netbird ssh` under a non-TTY context (some CI wrappers) where local terminal setup fails; NAT/idle timeouts killing the overlay session mid-shell.
Related errors
- dial %s: %w
- start port forwarding: %w
- execute command: %w
- local port forward %s: %w
- remote port forward %s: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/707e9d38cf65e400.
Report an issue: GitHub.