{"id":"b879c09b0b4540cd","repo":"rust-lang/cargo","slug":"invalid-url-cannot-be-a-base-urls-are-not-su","errorCode":null,"errorMessage":"invalid url `{}`: cannot-be-a-base-URLs are not supported","messagePattern":"invalid url `(.+?)`: cannot-be-a-base-URLs are not supported","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/util/canonical_url.rs","lineNumber":25,"sourceCode":"///\n/// A \"canonical\" url is only intended for internal comparison purposes in\n/// Cargo. It's to help paper over mistakes such as depending on\n/// `github.com/foo/bar` vs `github.com/foo/bar.git`. This is **only** for\n/// internal purposes within Cargo and provides no means to actually read the\n/// underlying string value of the `Url` it contains. This is intentional,\n/// because all fetching should still happen within the context of the original\n/// URL.\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]\npub struct CanonicalUrl(Url);\n\nimpl CanonicalUrl {\n    pub fn new(url: &Url) -> CargoResult<CanonicalUrl> {\n        let mut url = url.clone();\n\n        // cannot-be-a-base-urls (e.g., `github.com:rust-lang/rustfmt.git`)\n        // are not supported.\n        if url.cannot_be_a_base() {\n            anyhow::bail!(\n                \"invalid url `{}`: cannot-be-a-base-URLs are not supported\",\n                url\n            )\n        }\n\n        // Strip a trailing slash.\n        if url.path().ends_with('/') {\n            url.path_segments_mut().unwrap().pop_if_empty();\n        }\n\n        // Perform further canonicalization specific to git registries, which\n        // do not contain a `+` specifier.\n        if !url.scheme().contains('+') {\n            // For GitHub URLs specifically, just lower-case everything. GitHub\n            // treats both the same, but they hash differently, and we're gonna be\n            // hashing them. This wants a more general solution, and also we're\n            // almost certainly not using the same case conversion rules that GitHub\n            // does. (See issue #84)","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/rust-lang/cargo/blob/0e07a155371a6ce88ae53a2c00df940280c09a67/src/util/canonical_url.rs#L7-L43","documentation":"CanonicalUrl::new normalizes registry/git URLs for internal comparison and hashing, and it refuses URLs where url::Url::cannot_be_a_base() is true. Such URLs lack a hierarchical base (no scheme separator producing a path) — classic examples are SCP-style `host:path` strings like `github.com:rust-lang/rustfmt.git` or `git@github.com:owner/repo.git`. Cargo cannot apply its path-stripping/canonicalization logic to them, so it bails.","triggerScenarios":"Constructing a git dependency or registry source whose URL parses as cannot-be-a-base: passing an SCP-notation string (`host:path`) directly as a registry index URL or as a git dependency URL in Cargo.toml, or feeding such a Url into CanonicalUrl::new programmatically.","commonSituations":"Copying a GitHub SSH clone command's `git@github.com:owner/repo.git` argument into a Cargo.toml git dependency; using a registry index URL without an `https://`/`ssh://`/`git://` scheme; hand-building a url::Url from a bare `host:path` string.","solutions":["Prefix the URL with a proper scheme: use `ssh://git@github.com/owner/repo.git` instead of `git@github.com:owner/repo.git`.","For GitHub dependencies prefer `https://github.com/owner/repo.git`.","If using a registry index URL, ensure it begins with `https://` or `sparse+https://`.","Validate the URL parses with a scheme and a non-empty host before passing it to Cargo APIs."],"exampleFix":"# Cargo.toml before\ngit = \"git@github.com:owner/repo.git\"\n\n# after\ngit = \"ssh://git@github.com/owner/repo.git\"\n# or simpler\nhttps = \"https://github.com/owner/repo.git\"","handlingStrategy":"validation","validationCode":"use url::Url;\nfn is_cargo_safe_url(s: &str) -> Result<(), String> {\n    let u = Url::parse(s).map_err(|e| format!(\"not a URL: {e}\"))?;\n    if u.cannot_be_a_base() {\n        return Err(format!(\"{s} is a cannot-be-a-base URL; add a scheme like https:// or ssh://\"));\n    }\n    Ok(())\n}\n// call before constructing a git dependency / registry index URL","typeGuard":"fn is_valid_canonical_url(s: &str) -> bool {\n    Url::parse(s).map(|u| !u.cannot_be_a_base()).unwrap_or(false)\n}","tryCatchPattern":"match CanonicalUrl::new(&url) {\n    Ok(c) => use c,\n    Err(e) if e.to_string().contains(\"cannot-be-a-base\") => {\n        return Err(anyhow!(\"rewrite the URL with a scheme, e.g. ssh://{url}\"));\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always include a scheme (https://, ssh://, git://) on git/registry URLs in Cargo.toml.","Prefer HTTPS GitHub URLs to avoid SCP-notation confusion.","Lint manifests for URLs lacking `://`."],"tags":["url","canonicalization","git","validation"],"analyzedSha":"0e07a155371a6ce88ae53a2c00df940280c09a67","analyzedAt":"2026-08-06T01:46:58.334Z","schemaVersion":2}