{"record":{"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":null,"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/eb98b54bc9f3c74519f43d066cb3fd02ebc88df0/src/util/canonical_url.rs#L7-L43","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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://."],"exampleFix":"# before (Cargo.toml)\n# [dependencies]\n# foo = { git = \"github.com:org/foo.git\" }\n\n# after\n# [dependencies]\n# foo = { git = \"https://github.com/org/foo.git\" }","handlingStrategy":"validation","validationCode":"use url::Url;\n\nfn is_acceptable_registry_url(s: &str) -> Result<Url, String> {\n    let u = Url::parse(s).map_err(|e| e.to_string())?;\n    if u.cannot_be_a_base() {\n        return Err(format!(\"{s} is cannot-be-a-base; use a scheme-prefixed URL\"));\n    }\n    Ok(u)\n}\n\n// call before constructing CanonicalUrl / writing a git dependency:\n// let _ = is_acceptable_registry_url(index_url)?;","typeGuard":"fn url_has_scheme(u: &url::Url) -> bool {\n    !u.cannot_be_a_base()\n}","tryCatchPattern":"match CanonicalUrl::new(&url) {\n    Ok(c) => { /* use c */ }\n    Err(e) if e.to_string().contains(\"cannot-be-a-base\") => {\n        eprintln!(\"Rewrite the dependency URL to https:// or ssh:// form: {url}\");\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["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."],"tags":["url","git","configuration","validation"],"backgroundTag":null,"analyzedSha":"eb98b54bc9f3c74519f43d066cb3fd02ebc88df0","analyzedAt":"2026-08-11T17:42:36.556Z","contentChangedAt":"2026-08-11T17:42:36.556Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}