{"record":{"id":"7a023b9cc9f76d9e","repo":"sxyazi/yazi","slug":"e-7a023b","errorCode":null,"errorMessage":"{e}","messagePattern":"\\{e\\}","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"yazi-vfs/src/engine/sftp/conn.rs","lineNumber":73,"sourceCode":"}\n\nimpl Conn {\n\tpub(super) async fn roll(self) -> io::Result<deadpool::managed::Object<Self>> {\n\t\tuse deadpool::managed::PoolError;\n\n\t\tlet pool = *super::CONN.lock().entry(self.config).or_insert_with(|| {\n\t\t\tBox::leak(Box::new(\n\t\t\t\tdeadpool::managed::Pool::builder(self)\n\t\t\t\t\t.runtime(deadpool::Runtime::Tokio1)\n\t\t\t\t\t.max_size(8)\n\t\t\t\t\t.create_timeout(Some(Duration::from_secs(45)))\n\t\t\t\t\t.build()\n\t\t\t\t\t.unwrap(),\n\t\t\t))\n\t\t});\n\n\t\tpool.get().await.map_err(|e| match e {\n\t\t\tPoolError::Timeout(_) => io::Error::new(io::ErrorKind::TimedOut, e.to_string()),\n\t\t\tPoolError::Backend(e) => e,\n\t\t\tPoolError::Closed | PoolError::NoRuntimeSpecified | PoolError::PostCreateHook(_) => {\n\t\t\t\tio::Error::other(e.to_string())\n\t\t\t}\n\t\t})\n\t}\n\n\tasync fn connect(self) -> Result<russh::Channel<russh::client::Msg>, russh::Error> {\n\t\tlet pref = Arc::new(russh::client::Config {\n\t\t\tinactivity_timeout: Some(std::time::Duration::from_secs(60)),\n\t\t\tkeepalive_interval: Some(std::time::Duration::from_secs(10)),\n\t\t\t..Default::default()\n\t\t});\n\n\t\tlet session = if self.config.password.is_some() {\n\t\t\tself.connect_by_password(pref).await\n\t\t} else if !self.config.key_file.as_os_str().is_empty()\n\t\t\t&& !self.config.cert_file.as_os_str().is_empty()","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/sxyazi/yazi/blob/5f901b886b14de1f17460b6e52e9de5d67f8aba9/yazi-vfs/src/engine/sftp/conn.rs#L55-L91","documentation":"This error surfaces connection-establishment failures from the SFTP connection pool (`deadpool`) in `roll`. Pool timeouts become ErrorKind::TimedOut, backend errors are passed through unchanged, and everything else (pool closed, no runtime, post-create hook failure) becomes a generic io::Error with the pool error's text. It wraps whatever prevented obtaining a pooled SFTP connection.","triggerScenarios":"Acquiring a connection to a remote when the pool is exhausted (more concurrent ops than pool limit and the wait times out), the pool is shut down, the connection factory (backend) fails (bad host/key/auth), or the pool is used outside a tokio runtime.","commonSituations":"Slow or unreachable SSH host causing pool timeout, wrong SSH credentials/known_hosts making every Backend creation fail, too many parallel file operations saturating the pool, or dropping the tokio runtime while a connection is awaited.","solutions":["Fix the underlying cause reported in the message: check host reachability, SSH auth, and known_hosts for backend errors","Increase the SFTP connection pool timeout/size or reduce concurrency if you hit Timeout","Ensure all pool usage happens inside the tokio runtime (NoRuntimeSpecified)","Retry on TimedOut with backoff — transient network slowness is the most common cause"],"exampleFix":"// before\nlet conn = pool.get().await?; // Timeout on slow network\n// after\nmatch pool.get().await {\n    Ok(c) => c,\n    Err(PoolError::Timeout(_)) => return Err(io::Error::new(TimedOut, \"sftp pool timeout, retry\")),\n    Err(e) => return Err(map_pool_err(e)),\n}","handlingStrategy":"retry","validationCode":"// Reachability pre-check before issuing SFTP work\nlet ok = tokio::net::TcpStream::connect((host, port)).await.is_ok();\nif !ok { return Err(io::Error::new(io::ErrorKind::TimedOut, \"host unreachable\")); }","typeGuard":null,"tryCatchPattern":"match pool.get().await {\n    Err(PoolError::Timeout(_)) => backoff_retry(|| pool.get()).await,\n    Err(PoolError::Backend(e)) => return Err(e), // auth/host problem — don't blind-retry\n    Err(other) => return Err(io::Error::other(other.to_string())),\n    Ok(conn) => conn,\n}","preventionTips":["Retry only Timeout errors with backoff; Backend errors need credential/host fixes first","Keep concurrency within the pool size or raise the pool limit/timeout in config","Always run pool operations inside the tokio runtime","Pre-warm a connection when a remote mount is opened to surface auth issues early"],"tags":["sftp","network","connection-pool","timeout"],"backgroundTag":"connection-pool-exhausted","analyzedSha":"5f901b886b14de1f17460b6e52e9de5d67f8aba9","analyzedAt":"2026-09-02T18:38:25.566Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}