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
- Provide a nonempty repository URL (e.g. https://host/org/repo.git or git@host:org/repo.git)
- Remove any leading dash or stray characters from the configured URL
- 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
- Never build git command lines with unvalidated remote strings from user input
- Expand and check env-var/template placeholders before they reach the remote field
- Treat a leading '-' in any CLI-passed value as hostile and reject it early
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
- invalid repository origin
- `ref` must not start with `-`
- unsafe source repository path
- `url` must not start with `-`
- brew-cask: invalid
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)