sinelaw/fresh · error

--ssh-url expects an ssh:// URL, got

Error message

--ssh-url expects an ssh:// URL, got {:?}

What it means

parse_ssh_url_arg validates the --ssh-url CLI argument passed by spawn_server_detached when re-invoking the editor for a remote session. The URL must start with ssh://; anything else is a hard error because the argument is generated internally — a malformed value means the URL was corrupted between the two processes.

Solutions

  1. Check the exact value passed to --ssh-url; it must literally begin with ssh://
  2. If a user typo'd it, use the correct form: --ssh-url ssh://user@host/path
  3. If spawn_server_detached produced it, debug the argument construction/quoting there — this is an internal corruption per the doc comment
  4. Log the full argv at spawn time to catch mangling by intermediate shells

Example fix

// before
fresh --ssh-url host.example.com/repo
// after
fresh --ssh-url ssh://host.example.com/repo
Defensive patterns

Strategy: validation

Validate before calling

fn valid_ssh_url_arg(url: &str) -> bool {
    url.starts_with("ssh://")
}
// assert before spawning: debug_assert!(valid_ssh_url_arg(&built_url));

Try / catch

match parse_ssh_url_arg(&arg) {
    Err(e) if e.to_string().starts_with("--ssh-url expects") => {
        eprintln!("internal error: malformed --ssh-url '{arg}'; expected ssh://…");
        std::process::exit(2);
    }
    other => other?,
}

Prevention

When it happens

Trigger: The editor re-executes itself with --ssh-url and the argument lost its ssh:// prefix — quoting/word-splitting issues in the spawn command, shell interpolation mangling the URL, or a user manually invoking the binary with a bad --ssh-url value.

Common situations: Manual testing of the binary with --ssh-url host:path instead of ssh://host/path; a bug in spawn_server_detached that truncates or rewrites the argument; special characters in host/user names breaking quoting.

Understand the failure class

Background: "Unknown argument", "Invalid value", and "must be one of": invalid CLI argument errors explained — this error's family across 35 libraries.

Related errors


AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13). Data as JSON: /api/errors/6b82cc849fa117c4. Report an issue: GitHub.

Appendix: source

Thrown at crates/fresh-editor/src/main.rs:1456

        .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)))
}

/// Parse a standalone `ssh://…` URL passed via the internal
/// `--ssh-url` flag.  Accepts only the URL form (not scp-style) and
/// the URL must carry a path; anything else is a hard error because
/// this input comes from our own `spawn_server_detached` and a
/// malformed URL there means we corrupted it on the way over.
fn parse_ssh_url_arg(url: &str) -> AnyhowResult<RemoteLocation> {
    let rest = url
        .strip_prefix("ssh://")
        .ok_or_else(|| anyhow::anyhow!("--ssh-url expects an ssh:// URL, got {:?}", url))?;
    parse_ssh_url_rest(rest, default_ssh_user().as_deref()).map_err(|reason| {
        anyhow::anyhow!(
            "--ssh-url is not a valid ssh:// URL ({}): {:?}",
            reason,
            url
        )
    })
}

/// Parse a location that may be local, scp-style remote, or an
/// `ssh://` URL.
///
/// Accepted forms:
/// - local: `file`, `file:line`, `file:line:col`
/// - scp-style remote: `user@host:path[:line[:col]]`
/// - URL-style remote: `ssh://[user@]host[:port]/path[:line[:col]]`
///
/// When `ssh://` omits the user, the current login name (`$USER` /

View on GitHub (pinned to 67894ca546)