rust-lang/cargo · error
invalid url ` `: cannot-be-a-base-URLs are not supported
Error message
invalid url `{}`: cannot-be-a-base-URLs are not supported What it means
CanonicalUrl wraps a URL for registry-index keying and git-registry deduplication. URLs flagged cannot-be-a-base by the url crate (e.g. SCP-style `host:path` without a scheme) are rejected because Cargo needs absolute, comparable URLs for caching and resolution.
Solutions
- Use a fully-qualified URL with a scheme: `https://github.com/org/repo.git` or `ssh://git@github.com/org/repo.git`.
- For SSH, use the ssh:// form rather than the SCP shorthand.
- Validate registry index URLs in .cargo/config.toml all start with https://, http://, ssh://, or git://.
Example fix
# before (Cargo.toml)
# [dependencies]
# foo = { git = "github.com:org/foo.git" }
# after
# [dependencies]
# foo = { git = "https://github.com/org/foo.git" } Defensive patterns
Strategy: validation
Validate before calling
use url::Url;
fn is_acceptable_registry_url(s: &str) -> Result<Url, String> {
let u = Url::parse(s).map_err(|e| e.to_string())?;
if u.cannot_be_a_base() {
return Err(format!("{s} is cannot-be-a-base; use a scheme-prefixed URL"));
}
Ok(u)
}
// call before constructing CanonicalUrl / writing a git dependency:
// let _ = is_acceptable_registry_url(index_url)?; Type guard
fn url_has_scheme(u: &url::Url) -> bool {
!u.cannot_be_a_base()
} Try / catch
match CanonicalUrl::new(&url) {
Ok(c) => { /* use c */ }
Err(e) if e.to_string().contains("cannot-be-a-base") => {
eprintln!("Rewrite the dependency URL to https:// or ssh:// form: {url}");
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Always include a scheme (https://, ssh://, git://) on git dependencies and registry index URLs in Cargo.toml.
- Never paste SCP-style (`host:path`) remotes into manifests.
- Lint manifests in CI with `toml` parsing that rejects cannot-be-a-base URLs.
When it happens
Trigger: Constructing CanonicalUrl::new(&url) where url was parsed from an SCP-style string like `github.com:rust-lang/rustfmt.git` or `git@github.com:org/repo.git` (no scheme), typically via a git dependency or registry index URL in Cargo.toml/config.
Common situations: Copy-pasting an SCP-style GitHub remote into a Cargo git dependency; using an SSH alias shorthand as a registry index URL; git config remotes referenced by shorthand in manifest.
Related errors
- sparse registry url must end in a slash `/
- couldn't find repository name
- couldn't find username
- expect run ID in format…
- no path segments on url
AI-assisted analysis of rust-lang/cargo@eb98b54bc9 (2026-08-11).
Data as JSON: /api/errors/b879c09b0b4540cd.
Report an issue: GitHub.
Appendix: source
Thrown at src/util/canonical_url.rs:25
///
/// A "canonical" url is only intended for internal comparison purposes in
/// Cargo. It's to help paper over mistakes such as depending on
/// `github.com/foo/bar` vs `github.com/foo/bar.git`. This is **only** for
/// internal purposes within Cargo and provides no means to actually read the
/// underlying string value of the `Url` it contains. This is intentional,
/// because all fetching should still happen within the context of the original
/// URL.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct CanonicalUrl(Url);
impl CanonicalUrl {
pub fn new(url: &Url) -> CargoResult<CanonicalUrl> {
let mut url = url.clone();
// cannot-be-a-base-urls (e.g., `github.com:rust-lang/rustfmt.git`)
// are not supported.
if url.cannot_be_a_base() {
anyhow::bail!(
"invalid url `{}`: cannot-be-a-base-URLs are not supported",
url
)
}
// Strip a trailing slash.
if url.path().ends_with('/') {
url.path_segments_mut().unwrap().pop_if_empty();
}
// Perform further canonicalization specific to git registries, which
// do not contain a `+` specifier.
if !url.scheme().contains('+') {
// For GitHub URLs specifically, just lower-case everything. GitHub
// treats both the same, but they hash differently, and we're gonna be
// hashing them. This wants a more general solution, and also we're
// almost certainly not using the same case conversion rules that GitHub
// does. (See issue #84)View on GitHub (pinned to eb98b54bc9)