From 9d76bd12652f05c2a89846f12b764ce295b4db99 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 8 Jun 2026 10:48:09 +0200 Subject: [PATCH] remote: Do not swallow ssh errors (#58780) Release Notes: - Fixed non-descriptive error messages when remote agent processed disconnected --- crates/agent_servers/src/acp.rs | 2 +- crates/project/src/context_server_store.rs | 3 ++- crates/project/src/debugger/dap_store.rs | 2 +- crates/project/src/terminals.rs | 4 +++- crates/remote/src/remote_client.rs | 18 ------------------ crates/remote/src/transport/ssh.rs | 18 ++++++++++-------- 6 files changed, 17 insertions(+), 30 deletions(-) diff --git a/crates/agent_servers/src/acp.rs b/crates/agent_servers/src/acp.rs index d85f285437..d5f5ae376c 100644 --- a/crates/agent_servers/src/acp.rs +++ b/crates/agent_servers/src/acp.rs @@ -795,7 +795,7 @@ impl AcpConnection { project.remote_client().and_then(|client| { let template = client .read(cx) - .build_command_with_options( + .build_command( Some(command.path.display().to_string()), &command.args, &command.env.clone().into_iter().flatten().collect(), diff --git a/crates/project/src/context_server_store.rs b/crates/project/src/context_server_store.rs index 35651a7ff4..8dab25d8ab 100644 --- a/crates/project/src/context_server_store.rs +++ b/crates/project/src/context_server_store.rs @@ -20,7 +20,7 @@ use http_client::HttpClient; use itertools::Itertools; use rand::Rng as _; use registry::ContextServerDescriptorRegistry; -use remote::RemoteClient; +use remote::{Interactive, RemoteClient}; use rpc::{AnyProtoClient, TypedEnvelope, proto}; use settings::{Settings as _, SettingsStore}; use util::{ResultExt as _, rel_path::RelPath}; @@ -801,6 +801,7 @@ impl ContextServerStore { &response.env.into_iter().collect(), root_dir, None, + Interactive::Yes, ) })?; diff --git a/crates/project/src/debugger/dap_store.rs b/crates/project/src/debugger/dap_store.rs index e0594467f0..01aedbbad0 100644 --- a/crates/project/src/debugger/dap_store.rs +++ b/crates/project/src/debugger/dap_store.rs @@ -343,7 +343,7 @@ impl DapStore { } let command = remote.read_with(cx, |remote, _cx| { - remote.build_command_with_options( + remote.build_command( binary.command, &binary.arguments, &binary.envs, diff --git a/crates/project/src/terminals.rs b/crates/project/src/terminals.rs index 5908408f7c..46e78e297c 100644 --- a/crates/project/src/terminals.rs +++ b/crates/project/src/terminals.rs @@ -6,7 +6,7 @@ use async_channel::bounded; use futures::{FutureExt, future::Shared}; use itertools::Itertools as _; use language::LanguageName; -use remote::RemoteClient; +use remote::{Interactive, RemoteClient}; use settings::{Settings, SettingsLocation}; use std::{ borrow::Cow, @@ -558,6 +558,7 @@ impl Project { &env, None, None, + Interactive::Yes, )?; let mut command = new_std_command(command_template.program); command.args(command_template.args); @@ -631,6 +632,7 @@ fn create_remote_shell( &env, working_directory.map(|path| path.display().to_string()), None, + Interactive::Yes, )?; log::debug!("Connecting to a remote server: {:?}", command.program); diff --git a/crates/remote/src/remote_client.rs b/crates/remote/src/remote_client.rs index 993872b179..c0981d0706 100644 --- a/crates/remote/src/remote_client.rs +++ b/crates/remote/src/remote_client.rs @@ -930,24 +930,6 @@ impl RemoteClient { env: &HashMap, working_dir: Option, port_forward: Option<(u16, String, u16)>, - ) -> Result { - self.build_command_with_options( - program, - args, - env, - working_dir, - port_forward, - Interactive::Yes, - ) - } - - pub fn build_command_with_options( - &self, - program: Option, - args: &[String], - env: &HashMap, - working_dir: Option, - port_forward: Option<(u16, String, u16)>, interactive: Interactive, ) -> Result { let Some(connection) = self.remote_connection() else { diff --git a/crates/remote/src/transport/ssh.rs b/crates/remote/src/transport/ssh.rs index 1a8337dcd7..ac549a6e7c 100644 --- a/crates/remote/src/transport/ssh.rs +++ b/crates/remote/src/transport/ssh.rs @@ -1863,9 +1863,9 @@ fn build_command_posix( )); } - // -q suppresses the "Connection to ... closed." message that SSH prints when - // the connection terminates with -t (pseudo-terminal allocation) - args.push("-q".into()); + // LogLevel=ERROR suppresses the "Connection to ... closed." message while + // preserving SSH errors. + args.extend(["-o".into(), "LogLevel=ERROR".into()]); match interactive { // -t forces pseudo-TTY allocation (for interactive use) Interactive::Yes => args.push("-t".into()), @@ -1958,9 +1958,9 @@ fn build_command_windows( )); } - // -q suppresses the "Connection to ... closed." message that SSH prints when - // the connection terminates with -t (pseudo-terminal allocation) - args.push("-q".into()); + // LogLevel=ERROR suppresses the "Connection to ... closed." message while + // preserving SSH errors. + args.extend(["-o".into(), "LogLevel=ERROR".into()]); match interactive { // -t forces pseudo-TTY allocation (for interactive use) Interactive::Yes => args.push("-t".into()), @@ -2039,7 +2039,8 @@ mod tests { [ "-p", "2222", - "-q", + "-o", + "LogLevel=ERROR", "-t", "user@host", "cd \"$HOME\"/work && exec env 'INPUT_VA=val' remote_program arg1 arg2" @@ -2075,7 +2076,8 @@ mod tests { "2222", "-L", "1:foo:2", - "-q", + "-o", + "LogLevel=ERROR", "-t", "user@host", "cd && exec env 'INPUT_VA=val' /bin/fish -l"