jdx/mise · error

GitHub relay socket forwarding failed

Error message

GitHub relay socket forwarding failed

What it means

mise's GitHub relay lets a remote host borrow local GitHub credentials through a Unix socket forwarded over SSH (`ssh -O forward -R remote.sock:local.sock`). This error means the ssh multiplexed forward command exited non-zero, so the remote side has no socket to send GitHub requests through. mise throws it when the forwarding setup fails before the remote command starts.

Solutions

  1. Re-run the command; transient multiplexed-control failures often clear on a fresh connection
  2. Check the host's sshd_config for AllowStreamLocalForwarding/AllowTcpForwarding restrictions and enable forwarding
  3. Use a shorter staging directory path so the forwarded socket path fits the Unix socket length limit
  4. Run with --no-relay style opt-out and provide GitHub credentials directly on the remote host instead
  5. Delete a stale staging/github.sock on the remote before retrying

Example fix

# before: sshd_config on host blocks forwarding
AllowTcpForwarding no
# after
AllowTcpForwarding yes
AllowStreamLocalForwarding yes
Defensive patterns

Strategy: retry

Validate before calling

# preflight: confirm forwarding is permitted
ssh -o ExitOnForwardFailure=yes -o ControlMaster=no host true && ssh -G host | grep -Ei 'forwarding'

Try / catch

match start_relay(&session, staging, scope).await {
    Ok(relay) => relay,
    Err(e) if e.to_string().contains("relay socket forwarding failed") => {
        // retry once with a fresh connection, else fall back to remote credentials
        tokio::time::sleep(Duration::from_secs(2)).await;
        start_relay(&session, staging, scope).await?
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `start_relay` from `run_staged` or `ssh` (Unix only, relay enabled); `ssh -S control -O forward -R staging/github.sock:local-relay.sock host` returns a non-zero status, e.g. with ExitOnForwardFailure=yes.

Common situations: The SSH server on the host disables TCP/streamlocal forwarding (AllowStreamLocalForwarding no); the remote staging socket path already exists or is not writable; the multiplexed control socket died between connection and forward request; the local relay socket path exceeds the 108-char Unix socket limit.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


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

Appendix: source

Thrown at src/system/remote.rs:722

    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_spawnable("ssh").ok_or_else(|| eyre!("ssh not found"))?,
        host,
        relay: true,

View on GitHub (pinned to 533346cc37)