jdx/mise · error

setup repository URL must be nonempty and must not start…

Error message

setup repository URL must be nonempty and must not start with '-'

What it means

validate_url checks the setup repository URL before any git network command is built with it. An empty URL, or one beginning with '-' after leading whitespace, is rejected: the empty case is meaningless, and a leading dash would be interpreted by git as a command-line flag, enabling argument injection. This guard runs before every fetch/push/ls-remote against the remote.

Solutions

  1. Provide a nonempty repository URL (e.g. https://host/org/repo.git or git@host:org/repo.git)
  2. Remove any leading dash or stray characters from the configured URL
  3. Check where the URL is sourced (env var, template, config) and ensure it expands to a real URL

Example fix

// before
let url = std::env::var("HISTORY_REMOTE").unwrap_or_default(); // ""
Remote::new(&repo, &url).ls_remote()?; // bails
// after
let url = std::env::var("HISTORY_REMOTE")?;
anyhow::ensure!(!url.trim().is_empty(), "HISTORY_REMOTE must be set");
Remote::new(&repo, &url).ls_remote()?;
Defensive patterns

Strategy: validation

Validate before calling

fn url_ok(v: &str) -> bool {
    let t = v.trim();
    !t.is_empty() && !t.starts_with('-')
}

Type guard

function isValidRemoteUrl(v: unknown): v is string {
  return typeof v === "string" && v.trim().length > 0 && !v.trim().startsWith("-");
}

Try / catch

match validate_url(&raw) {
    Ok(()) => { /* proceed with network call */ }
    Err(e) => {
        log::error("rejecting setup repository URL: {e}");
        return Err(e);
    }
}

Prevention

When it happens

Trigger: Calling Network::fetch_with_depth, push, symbolic_head, or ls_remote — or the malformed_http_remotes_fail_without_echoing_credentials path — with a URL that is empty/whitespace-only or starts with '-' (e.g. from an unexpanded template or a config value like "--upload-pack=...").

Common situations: A placeholder URL left unfilled in configuration; an environment variable interpolating to an empty string; a crafted or copy-pasted remote string attempting option injection into the git invocation.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/cbf4163796520e08. Report an issue: GitHub.

Appendix: source

Thrown at src/system/history/sync/network.rs:23

use eyre::{Result, bail};

use crate::system::history::shadow::HistoryRepo;

/// The fetched setup branch head.
pub(crate) const UPSTREAM_REF: &str = "refs/remotes/origin/setup";

/// A Git transport failed, as distinct from an invalid local configuration,
/// encryption policy, or reconciliation plan.
#[derive(Debug, thiserror::Error)]
#[error("{0}")]
pub(crate) struct NetworkError(pub String);

/// Authentication belongs in a credential helper or SSH agent, never in
/// persisted connection URLs or the errors recorded in history health.
pub(crate) fn validate_url(value: &str) -> Result<()> {
    if value.trim().is_empty() || value.trim_start().starts_with('-') {
        bail!("setup repository URL must be nonempty and must not start with '-'");
    }
    let http_like = value
        .trim_start()
        .get(..5)
        .is_some_and(|prefix| prefix.eq_ignore_ascii_case("http:"))
        || value
            .trim_start()
            .get(..6)
            .is_some_and(|prefix| prefix.eq_ignore_ascii_case("https:"));
    if http_like && url::Url::parse(value).is_err() {
        bail!("invalid HTTP setup repository URL; use a Git credential helper for authentication");
    }
    if let Ok(url) = url::Url::parse(value) {
        let http = matches!(url.scheme(), "http" | "https");
        if url.password().is_some()
            || (http
                && (!url.username().is_empty()
                    || url.query().is_some()

View on GitHub (pinned to 533346cc37)