{"record":{"id":"6bc515de4826541a","repo":"sinelaw/fresh","slug":"cannot-mix-local-and-remote-files-use-either-local-paths-or","errorCode":null,"errorMessage":"Cannot mix local and remote files. Use either local paths or remote paths (ssh:// or user@host:path).","messagePattern":"Cannot mix local and remote files\\. Use either local paths or remote paths \\(ssh:// or user@host:path\\)\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fresh-editor/src/main.rs","lineNumber":1440,"sourceCode":"    }\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)))\n}\n\n/// Parse a standalone `ssh://…` URL passed via the internal\n/// `--ssh-url` flag.  Accepts only the URL form (not scp-style) and\n/// the URL must carry a path; anything else is a hard error because\n/// this input comes from our own `spawn_server_detached` and a\n/// malformed URL there means we corrupted it on the way over.\nfn parse_ssh_url_arg(url: &str) -> AnyhowResult<RemoteLocation> {\n    let rest = url\n        .strip_prefix(\"ssh://\")\n        .ok_or_else(|| anyhow::anyhow!(\"--ssh-url expects an ssh:// URL, got {:?}\", url))?;\n    parse_ssh_url_rest(rest, default_ssh_user().as_deref()).map_err(|reason| {\n        anyhow::anyhow!(","sourceCodeStart":1422,"sourceCodeEnd":1458,"githubUrl":"https://github.com/sinelaw/fresh/blob/67894ca5463dbd7a89bb31add4627c27d6b79d83/crates/fresh-editor/src/main.rs#L1422-L1458","documentation":"An invocation may contain either local file paths or remote paths (ssh:// or user@host:path), not both. After parsing, if any location is Local while others are remote, the parser bails. This prevents ambiguous session semantics (local buffers vs remote SSH sessions in one window).","triggerScenarios":"Invoking e.g. `fresh notes.txt alice@host:/tmp/x.txt` — parsed locations contain both ParsedLocation::Local and ParsedLocation::Remote variants.","commonSituations":"Shell completion or scripts appending a local file to a remote-targeted command; habitually adding `.` or a local scratch file alongside ssh targets; mis-remembered syntax where a path looks remote but parses as local (or vice versa).","solutions":["Split the invocation: open local files and remote files in separate commands","Remove the stray local path from the remote-targeted invocation","Check each argument parses as the intended kind (ssh:// prefix or user@host:path for remote)","Update wrapper scripts that always append a local file"],"exampleFix":"// before\nfresh notes.txt deploy@server:/var/log/app.log\n// after\nfresh notes.txt\nfresh deploy@server:/var/log/app.log","handlingStrategy":"validation","validationCode":"let args: Vec<&str> = std::env::args().skip(1).collect();\nlet has_remote = args.iter().any(|a| a.starts_with(\"ssh://\") || a.contains('@'));\nlet has_local = args.iter().any(|a| !a.starts_with(\"ssh://\") && !a.contains('@') && std::path::Path::new(a).exists());\nif has_remote && has_local { eprintln!(\"do not mix local and remote paths\"); }","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(\"mix local and remote\") => eprintln!(\"split into separate invocations\"),\n    Err(e) => eprintln!(\"{e}\"),\n    Ok(()) => {},\n}","preventionTips":["Group arguments by kind before invoking the editor","Check wrapper scripts that append local files unconditionally","Verify each path parses as the intended local/remote kind"],"tags":["cli","ssh","remote","arguments"],"backgroundTag":"mutually-exclusive-options","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"}