nikivdev/code · error · anyhow::Error
ssh-agent failed: {}
Error message
ssh-agent failed: {} What it means
ensure_flow_agent spawns `ssh-agent -a <sock> -s` and checks its exit status; if the process exits nonzero the captured stderr is wrapped in this message and returned. It means the local ssh-agent could not be started, so no agent socket is available for SSH operations.
Source
Thrown at src/ssh.rs:216
if sock.exists() {
if probe_agent(&sock) {
return Ok(sock);
}
let _ = fs::remove_file(&sock);
}
let state_path = flow_agent_state_path();
if let Some(parent) = state_path.parent() {
fs::create_dir_all(parent)?;
}
let output = Command::new("ssh-agent")
.args(["-a", sock.to_string_lossy().as_ref(), "-s"])
.output()
.context("failed to start ssh-agent")?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
bail!("ssh-agent failed: {}", stderr.trim());
}
let stdout = String::from_utf8_lossy(&output.stdout);
let pid = parse_agent_output(&stdout, "SSH_AGENT_PID")
.and_then(|val| val.parse::<u32>().ok())
.context("failed to parse ssh-agent pid")?;
let sock_path = parse_agent_output(&stdout, "SSH_AUTH_SOCK")
.map(PathBuf::from)
.unwrap_or_else(|| sock.clone());
let state = FlowAgentState {
pid,
sock: sock_path.clone(),
};
let content = serde_json::to_string_pretty(&state)?;
fs::write(&state_path, content)?;
Ok(sock_path)View on GitHub (pinned to a747e741ae)
Solutions
- Remove any stale socket file at the target path and retry
- Shorten the socket path (shorter temp dir) if it exceeds ~104-108 characters
- Ensure openssh-client (ssh-agent) is installed and on PATH
- Check permissions on the directory holding the socket
Example fix
// before: stale socket causes agent bind failure
.output()
.context("failed to start ssh-agent")?;
// after: clear stale socket first
if sock.exists() { let _ = std::fs::remove_file(&sock); }
let output = Command::new("ssh-agent")
.args(["-a", sock.to_string_lossy().as_ref(), "-s"])
.output()
.context("failed to start ssh-agent")?; Defensive patterns
Strategy: fallback
Validate before calling
let sock = agent_socket_path();
if sock.as_os_str().len() >= 108 {
bail!("socket path too long for unix sockets: {}", sock.display());
}
if sock.exists() {
let _ = std::fs::remove_file(&sock); // clear stale socket
}
if which::which("ssh-agent").is_err() {
bail!("ssh-agent not installed; install openssh-client");
} Try / catch
match ensure_flow_agent() {
Ok(agent) => use_agent(agent),
Err(e) if e.to_string().contains("ssh-agent failed") => {
eprintln!("agent start failed: {e:#}; falling back to existing SSH_AUTH_SOCK");
std::env::var("SSH_AUTH_SOCK").map(Agent::Existing)?
}
Err(e) => return Err(e),
} Prevention
- Keep socket paths under ~104 characters
- Remove stale sockets from crashed runs before starting a new agent
- Install openssh-client in containers/minimal images
- Fall back to a pre-existing SSH_AUTH_SOCK when spawning fails
When it happens
Trigger: ssh-agent binary missing or failing to bind the requested socket path; socket path too long (>108 chars on Unix domain sockets); stale socket file already exists at the path; permission denied on the socket directory.
Common situations: Long TMPDIR paths exceeding Unix socket path limits; leftover socket from a crashed previous run; read-only or noexec temp directory; minimal container images without openssh-client installed.
Related errors
- git config --global {} failed
- git config --global --add {} failed
- ssh-keygen failed
- editor exited with status {}
- suggested command exited unsuccessfully with status {}
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/8489f07314ae9987.
Report an issue: GitHub.