{"record":{"id":"fa38971f453cab29","repo":"sinelaw/fresh","slug":"cannot-open-files-from-multiple-remote-hosts-first-found","errorCode":null,"errorMessage":"Cannot open files from multiple remote hosts. First: {}@{}, found: {}@{}","messagePattern":"Cannot open files from multiple remote hosts\\. First: (.+?)@(.+?), found: (.+?)@(.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fresh-editor/src/main.rs","lineNumber":1427,"sourceCode":"        .map(|f| parse_location(f))\n        .collect::<AnyhowResult<Vec<_>>>()?;\n\n    let remotes: Vec<&RemoteLocation> = parsed\n        .iter()\n        .filter_map(|loc| match loc {\n            ParsedLocation::Remote(r) => Some(r),\n            ParsedLocation::Local(_) => None,\n        })\n        .collect();\n\n    if remotes.is_empty() {\n        return Ok(None);\n    }\n\n    let first = remotes[0];\n    for r in &remotes[1..] {\n        if r.user != first.user || r.host != first.host || r.port != first.port {\n            anyhow::bail!(\n                \"Cannot open files from multiple remote hosts. First: {}@{}, found: {}@{}\",\n                first.user,\n                first.host,\n                r.user,\n                r.host\n            );\n        }\n    }\n    if parsed\n        .iter()\n        .any(|loc| matches!(loc, ParsedLocation::Local(_)))\n    {\n        anyhow::bail!(\n            \"Cannot mix local and remote files. Use either local paths or remote paths (ssh:// or user@host:path).\"\n        );\n    }\n\n    Ok(Some(remote_location_to_ssh_url(first)))","sourceCodeStart":1409,"sourceCodeEnd":1445,"githubUrl":"https://github.com/sinelaw/fresh/blob/67894ca5463dbd7a89bb31add4627c27d6b79d83/crates/fresh-editor/src/main.rs#L1409-L1445","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nfresh alice@build.example.com:/etc/app.conf root@build.example.com:/etc/db.conf\n// after\nfresh alice@build.example.com:/etc/app.conf\nfresh root@build.example.com:/etc/db.conf  # separate invocation","handlingStrategy":"validation","validationCode":"let remotes: Vec<&str> = args.iter().filter(|a| a.contains('@') || a.starts_with(\"ssh://\")).map(|a| a.as_str()).collect();\nlet hosts: std::collections::HashSet<_> = remotes.iter().map(|r| r.split('@').last().unwrap_or(r).split(':').next().unwrap_or(r)).collect();\nif hosts.len() > 1 { eprintln!(\"files span multiple remote hosts\"); }","typeGuard":"fn is_remote_spec(s: &str) -> bool { s.starts_with(\"ssh://\") || (s.contains('@') && s.contains(':')) }","tryCatchPattern":"match editor::launch(args) {\n    Err(e) if e.to_string().contains(\"multiple remote hosts\") => eprintln!(\"open one host per session\"),\n    Err(e) => eprintln!(\"{e}\"),\n    Ok(()) => {},\n}","preventionTips":["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"],"tags":["cli","ssh","remote"],"backgroundTag":"invalid-argument-value","analyzedSha":"67894ca5463dbd7a89bb31add4627c27d6b79d83","analyzedAt":"2026-09-13T15:04:03.701Z","contentChangedAt":"2026-09-13T15:04:03.701Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}