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

  1. Remove any stale socket file at the target path and retry
  2. Shorten the socket path (shorter temp dir) if it exceeds ~104-108 characters
  3. Ensure openssh-client (ssh-agent) is installed and on PATH
  4. 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

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


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/8489f07314ae9987. Report an issue: GitHub.