sinelaw/fresh · error
Cannot open files from multiple remote hosts. First
Error message
Cannot open files from multiple remote hosts. First: {}@{}, found: {}@{} What it means
All remote file arguments in one invocation must come from the same user@host:port. When the parsed remote locations differ in user, host, or port, the parser bails naming the first and the conflicting remote. A single editor session can only attach to one remote host.
Solutions
- Run one editor instance per remote host
- Open remote files in separate invocations or editor tabs/sessions
- Normalize the user@host:port so all files reference the same remote
- If multi-host is genuinely needed, use a session manager or split into multiple terminal windows
Example fix
// before fresh alice@build.example.com:/etc/app.conf root@build.example.com:/etc/db.conf // after fresh alice@build.example.com:/etc/app.conf fresh root@build.example.com:/etc/db.conf # separate invocation
Defensive patterns
Strategy: validation
Validate before calling
let remotes: Vec<&str> = args.iter().filter(|a| a.contains('@') || a.starts_with("ssh://")).map(|a| a.as_str()).collect();
let hosts: std::collections::HashSet<_> = remotes.iter().map(|r| r.split('@').last().unwrap_or(r).split(':').next().unwrap_or(r)).collect();
if hosts.len() > 1 { eprintln!("files span multiple remote hosts"); } Type guard
fn is_remote_spec(s: &str) -> bool { s.starts_with("ssh://") || (s.contains('@') && s.contains(':')) } Try / catch
match editor::launch(args) {
Err(e) if e.to_string().contains("multiple remote hosts") => eprintln!("open one host per session"),
Err(e) => eprintln!("{e}"),
Ok(()) => {},
} Prevention
- Keep one user@host per editor invocation
- Note that differing port or username counts as a different remote
- Use separate editor instances or tabs for multi-host work
When it happens
Trigger: Invoking e.g. `fresh ssh://alice@host1:/a.txt bob@host2:/b.txt` or `fresh alice@host1:/a.txt root@host1:/b.txt` — parsed remotes[1..] differ from remotes[0] in user, host, or port.
Common situations: Mixing files from dev and staging servers in one command; forgetting a username differs (alice@ vs root@ on same host); different ports (host:2222 vs host) counting as different remotes.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Cannot mix local and remote files. Use either local paths…
- Cannot mix local and remote files. Use either local paths…
- --ssh-url expects an ssh:// URL, got
- --ssh-url is not a valid ssh:// URL
- invalid ssh:// URL : . To open a local file with this name…
AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13).
Data as JSON: /api/errors/fa38971f453cab29.
Report an issue: GitHub.
Appendix: source
Thrown at crates/fresh-editor/src/main.rs:1427
.map(|f| parse_location(f))
.collect::<AnyhowResult<Vec<_>>>()?;
let remotes: Vec<&RemoteLocation> = parsed
.iter()
.filter_map(|loc| match loc {
ParsedLocation::Remote(r) => Some(r),
ParsedLocation::Local(_) => None,
})
.collect();
if remotes.is_empty() {
return Ok(None);
}
let first = remotes[0];
for r in &remotes[1..] {
if r.user != first.user || r.host != first.host || r.port != first.port {
anyhow::bail!(
"Cannot open files from multiple remote hosts. First: {}@{}, found: {}@{}",
first.user,
first.host,
r.user,
r.host
);
}
}
if parsed
.iter()
.any(|loc| matches!(loc, ParsedLocation::Local(_)))
{
anyhow::bail!(
"Cannot mix local and remote files. Use either local paths or remote paths (ssh:// or user@host:path)."
);
}
Ok(Some(remote_location_to_ssh_url(first)))View on GitHub (pinned to 67894ca546)