jdx/mise · error

GitHub relay socket forwarding failed

Error message

GitHub relay socket forwarding failed

What it means

start_relay launches an SSH process (with -R/remote-forward args built around relay.socket()) to forward a socket to GitHub for remote operations. If the ssh subprocess exits non-zero, mise bails with this error because the relay tunnel could not be established, and no GitHub traffic can flow over it.

Source

Thrown at src/system/remote.rs:720

    let relay = crate::github_relay::unix::Relay::start(scope, &session.host.name).await?;
    let control = session
        .control_path
        .as_ref()
        .ok_or_else(|| eyre!("relay requires an owned SSH control connection"))?;
    let status = tokio::process::Command::new(&session.ssh)
        .kill_on_drop(true)
        .arg("-S")
        .arg(control)
        .args(["-O", "forward", "-o", "ExitOnForwardFailure=yes", "-R"])
        .arg(format!(
            "{staging}/github.sock:{}",
            relay.socket().display()
        ))
        .arg(session.host.destination())
        .status()
        .await?;
    if !status.success() {
        bail!("GitHub relay socket forwarding failed");
    }
    Ok(relay)
}

#[cfg(unix)]
pub(crate) async fn ssh(
    host: &RemoteHost,
    scope: crate::github_relay::Scope,
    command: &[String],
) -> Result<()> {
    crate::ui::ctrlc::exit_on_ctrl_c(false);
    let directory = tempfile::Builder::new()
        .prefix("mise-ssh-")
        .tempdir_in("/tmp")?;
    let session = SshSession {
        ssh: crate::file::which("ssh").ok_or_else(|| eyre!("ssh not found"))?,
        host,
        relay: true,

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Run the same ssh command manually (host shown after relay.socket() in the error context) to see the real SSH error
  2. Verify SSH key/auth works: ssh -T <host destination>
  3. Check the remote sshd config allows TCP forwarding (AllowTcpForwarding yes)
  4. Confirm the host destination and network/VPN connectivity
  5. Inspect relay.socket() permissions on unix; the local socket must be accessible to ssh

Example fix

// before: opaque failure
if !status.success() {
    bail!("GitHub relay socket forwarding failed");
}
// after: surface ssh stderr
if !status.success() {
    bail!("GitHub relay socket forwarding failed (ssh exited {status}); run ssh with -vvv to diagnose");
}
Defensive patterns

Strategy: retry

Validate before calling

const ok = await new Promise(res => { const p = spawn('ssh', ['-o','BatchMode=yes','-o','ConnectTimeout=5', host, 'true']); p.on('exit', c => res(c === 0)); });

Try / catch

try { await startRelay(); } catch (e) { if (String(e).includes('relay socket forwarding failed')) { await sshDiagnose(host); } throw e; }

Prevention

When it happens

Trigger: The ssh command spawned by start_relay (invoked from run_staged or ssh) returns a non-zero exit status — e.g. bad SSH credentials/key, unreachable host, rejected port in the relay destination, or sshd refusing the forward.

Common situations: Developers running `mise run-staged` or remote SSH-backed workflows hit this when their ~/.ssh/config has an Alias that no longer resolves, the remote host changed its sshd MaxSessions/AllowTcpForwarding settings, or a VPN is down so the host destination is unreachable.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/500f7350a2e22719. Report an issue: GitHub.