{"record":{"id":"500f7350a2e22719","repo":"jdx/mise","slug":"github-relay-socket-forwarding-failed","errorCode":null,"errorMessage":"GitHub relay socket forwarding failed","messagePattern":"GitHub relay socket forwarding failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/remote.rs","lineNumber":720,"sourceCode":"    let relay = crate::github_relay::unix::Relay::start(scope, &session.host.name).await?;\n    let control = session\n        .control_path\n        .as_ref()\n        .ok_or_else(|| eyre!(\"relay requires an owned SSH control connection\"))?;\n    let status = tokio::process::Command::new(&session.ssh)\n        .kill_on_drop(true)\n        .arg(\"-S\")\n        .arg(control)\n        .args([\"-O\", \"forward\", \"-o\", \"ExitOnForwardFailure=yes\", \"-R\"])\n        .arg(format!(\n            \"{staging}/github.sock:{}\",\n            relay.socket().display()\n        ))\n        .arg(session.host.destination())\n        .status()\n        .await?;\n    if !status.success() {\n        bail!(\"GitHub relay socket forwarding failed\");\n    }\n    Ok(relay)\n}\n\n#[cfg(unix)]\npub(crate) async fn ssh(\n    host: &RemoteHost,\n    scope: crate::github_relay::Scope,\n    command: &[String],\n) -> Result<()> {\n    crate::ui::ctrlc::exit_on_ctrl_c(false);\n    let directory = tempfile::Builder::new()\n        .prefix(\"mise-ssh-\")\n        .tempdir_in(\"/tmp\")?;\n    let session = SshSession {\n        ssh: crate::file::which(\"ssh\").ok_or_else(|| eyre!(\"ssh not found\"))?,\n        host,\n        relay: true,","sourceCodeStart":702,"sourceCodeEnd":738,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/remote.rs#L702-L738","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Run the same ssh command manually (host shown after relay.socket() in the error context) to see the real SSH error","Verify SSH key/auth works: ssh -T <host destination>","Check the remote sshd config allows TCP forwarding (AllowTcpForwarding yes)","Confirm the host destination and network/VPN connectivity","Inspect relay.socket() permissions on unix; the local socket must be accessible to ssh"],"exampleFix":"// before: opaque failure\nif !status.success() {\n    bail!(\"GitHub relay socket forwarding failed\");\n}\n// after: surface ssh stderr\nif !status.success() {\n    bail!(\"GitHub relay socket forwarding failed (ssh exited {status}); run ssh with -vvv to diagnose\");\n}","handlingStrategy":"retry","validationCode":"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)); });","typeGuard":null,"tryCatchPattern":"try { await startRelay(); } catch (e) { if (String(e).includes('relay socket forwarding failed')) { await sshDiagnose(host); } throw e; }","preventionTips":["Smoke-test SSH auth (ssh -o BatchMode=yes host true) before relayed operations","Keep sshd AllowTcpForwarding enabled on relay hosts","Pin known-good SSH host keys and config aliases"],"tags":["ssh","network","remote","process-exit"],"backgroundTag":"http-request-failed","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}