jdx/mise · error
SSH_CONNECTION must contain client address/port and server…
Error message
SSH_CONNECTION must contain client address/port and server address/port
What it means
The library parses the SSH_CONNECTION environment variable, which must contain exactly four whitespace-separated fields: client address, client port, server address, server port. When the variable is missing, empty, or has a different field count, parsing bails with this message. This is typically used to derive the connecting peer's address for dynamic firewall rules.
Solutions
- Run the command inside a normal SSH session so SSH_CONNECTION is set to four fields.
- Verify with `echo $SSH_CONNECTION` that it has exactly four whitespace-separated fields before invoking.
- If running under systemd/tmux/sudo, propagate SSH_CONNECTION explicitly (e.g. `sudo --preserve-env=SSH_CONNECTION` or PassEnvironment).
- If no SSH context applies, supply the peer/server addresses explicitly instead of relying on SSH_CONNECTION.
Example fix
// before $ mise firewall bootstrap # run locally, SSH_CONNECTION unset -> error // after $ ssh user@host $ echo $SSH_CONNECTION # e.g. 203.0.113.7 51234 10.0.0.5 22 $ mise firewall bootstrap
Defensive patterns
Strategy: validation
Validate before calling
fn has_valid_ssh_connection() -> bool {
std::env::var("SSH_CONNECTION")
.map(|v| v.split_ascii_whitespace().count() == 4)
.unwrap_or(false)
} Try / catch
match parse_ssh_connection(&std::env::var("SSH_CONNECTION").unwrap_or_default()) {
Err(_) => eprintln!("run inside an SSH session or pass addresses explicitly"),
Ok(conn) => { /* use conn.peer / conn.server */ }
} Prevention
- Verify SSH_CONNECTION exists before firewall bootstrap over SSH
- Preserve SSH_CONNECTION through sudo/systemd/tmux
- Fall back to explicit address arguments when no SSH context exists
- Log the parsed connection for debugging in bootstrap scripts
When it happens
Trigger: Calling parse_ssh_connection when SSH_CONNECTION is unset or empty (not invoked over SSH), or contains fewer/more than 4 whitespace-separated fields (e.g. only "1.2.3.4 22").
Common situations: Running a bootstrap/firewall command in a local shell, CI job, systemd service, or tmux where SSH_CONNECTION is not propagated; custom SSH setups or proxies that alter the variable; shell quoting collapsing fields.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- refusing firewall default incoming
- refusing firewall default incoming
- refusing firewall default incoming
- refusing firewall default incoming
- refusing firewall default incoming
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/65b598badf012ea7.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/firewall.rs:2053
Ok(())
}
fn validate_interface(interface: &str) -> Result<String> {
if interface.is_empty()
|| interface.len() > 15
|| !interface
.bytes()
.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_' | b'.' | b':'))
{
bail!("firewall interface '{interface}' is invalid");
}
Ok(interface.to_string())
}
fn parse_ssh_connection(value: &str) -> Result<SshConnection> {
let fields = value.split_ascii_whitespace().collect::<Vec<_>>();
if fields.len() != 4 {
bail!("SSH_CONNECTION must contain client address/port and server address/port");
}
Ok(SshConnection {
peer: fields[0].parse()?,
server: fields[2].parse()?,
server_port: fields[3].parse()?,
})
}
/// Detect an sshd ancestor when SSH_CONNECTION was stripped by sudo, env -i,
/// or a wrapper. `None` fails closed because ancestry could not be inspected.
fn ssh_ancestor_present() -> Option<bool> {
let mut pid = std::process::id();
let mut visited = HashSet::new();
for _ in 0..64 {
if !visited.insert(pid) {
return None;
}
let comm = fs::read_to_string(format!("/proc/{pid}/comm")).ok()?;View on GitHub (pinned to 533346cc37)