{"record":{"id":"d1697ee800b84e98","repo":"dbt-labs/dbt-core","slug":"semver-build-metadata-not-supported-in-semver","errorCode":null,"errorMessage":"SemVer build metadata not supported in {semver:?}","messagePattern":"SemVer build metadata not supported in (.+?)","errorType":"validation","errorClass":"anyhow","httpStatus":null,"severity":"error","filePath":"crates/dbt-ci/src/release_version.rs","lineNumber":47,"sourceCode":"}\n\nimpl ParsedReleaseVersion<'_> {\n    pub(crate) fn to_pep440(&self) -> String {\n        let Some((lane, n)) = self.prerelease else {\n            return self.base.to_string();\n        };\n        match lane {\n            PreReleaseLane::Alpha => format!(\"{}a{n}\", self.base),\n            PreReleaseLane::Beta => format!(\"{}b{n}\", self.base),\n            PreReleaseLane::Rc => format!(\"{}rc{n}\", self.base),\n            PreReleaseLane::Dev => format!(\"{}.dev{n}\", self.base),\n        }\n    }\n}\n\npub(crate) fn parse_release_version(semver: &str) -> Result<ParsedReleaseVersion<'_>> {\n    if semver.contains('+') {\n        bail!(\"SemVer build metadata not supported in {semver:?}\");\n    }\n    let (base, pre) = match semver.split_once('-') {\n        Some((b, p)) => (b, Some(p)),\n        None => (semver, None),\n    };\n    let parts: Vec<&str> = base.split('.').collect();\n    let well_formed = parts.len() == 3\n        && parts\n            .iter()\n            .all(|p| !p.is_empty() && p.chars().all(|c| c.is_ascii_digit()));\n    if !well_formed {\n        bail!(\"expected X.Y.Z, got {base:?} in {semver:?}\");\n    }\n    let Some(pre) = pre else {\n        return Ok(ParsedReleaseVersion {\n            base,\n            prerelease: None,\n        });","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-ci/src/release_version.rs#L29-L65","documentation":"parse_release_version in crates/dbt-ci/src/release_version.rs rejects any SemVer string containing '+' because build metadata has no representation in PEP 440 release versions used by PyPI. The error exists to force callers to strip build metadata before converting a SemVer version to a Python release version.","triggerScenarios":"Calling parse_release_version, validate_release_version, or semver_to_pep440 with a version like \"1.2.3+build.5\" or \"1.2.3+abc123\" (typically a version auto-generated with a git SHA suffix).","commonSituations":"CI injects build metadata into the version (common with cargo-release or setuptools_scm-style schemes) and that version is passed directly to the release pipeline; developers copy a local dev version into the release config.","solutions":["Remove the '+' build-metadata suffix from the version string before invoking the release pipeline.","If the metadata matters, encode the equivalent information in a pre-release lane (e.g. 1.2.3-rc.1) instead.","Adjust your release tooling (e.g. cargo release config or CI version step) to emit plain X.Y.Z[-pre.N] versions."],"exampleFix":"// before\nlet version = \"1.2.3+gdeadbeef\";\nparse_release_version(version)?;\n// after\nlet version = version.split('+').next().unwrap(); // \"1.2.3\"\nparse_release_version(version)?;","handlingStrategy":"validation","validationCode":"fn validate_no_build_metadata(semver: &str) -> Result<(), String> {\n    if semver.contains('+') {\n        return Err(format!(\"strip '+' build metadata from {semver:?}\"));\n    }\n    Ok(())\n}","typeGuard":"fn is_plain_release_version(v: &str) -> bool { !v.contains('+') }","tryCatchPattern":"match parse_release_version(v) {\n    Ok(parsed) => use(parsed),\n    Err(e) if e.to_string().contains(\"build metadata\") => {\n        let stripped = v.split('+').next().unwrap();\n        parse_release_version(stripped)?\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Configure version tooling to never emit '+' build metadata in release versions.","Strip build metadata at the CI boundary where the version is first produced.","Validate the version string early in the pipeline, before builds run."],"tags":["semver","versioning","validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"0267ce9170576975b76b64ce856b2e5848e96617","analyzedAt":"2026-09-07T21:53:39.732Z","contentChangedAt":"2026-09-07T21:53:39.732Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}