{"record":{"id":"bf8e6e8a4c1c9f8a","repo":"rust-lang/cargo","slug":"found-duplicate-binary-artifact","errorCode":null,"errorMessage":"Found {} duplicate binary artifact{}","messagePattern":"Found (.+?) duplicate binary artifact(.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/workspace/dependency.rs","lineNumber":669,"sourceCode":"        })\n    }\n\n    fn validate(kinds: Vec<ArtifactKind>) -> CargoResult<Vec<ArtifactKind>> {\n        if kinds.iter().any(|k| matches!(k, ArtifactKind::AllBinaries))\n            && kinds\n                .iter()\n                .any(|k| matches!(k, ArtifactKind::SelectedBinary(_)))\n        {\n            anyhow::bail!(\n                \"Cannot specify both 'bin' and 'bin:<name>' binary artifacts, as 'bin' selects all available binaries.\"\n            );\n        }\n        let mut kinds_without_dupes = kinds.clone();\n        kinds_without_dupes.sort();\n        kinds_without_dupes.dedup();\n        let num_dupes = kinds.len() - kinds_without_dupes.len();\n        if num_dupes != 0 {\n            anyhow::bail!(\n                \"Found {} duplicate binary artifact{}\",\n                num_dupes,\n                (num_dupes > 1).then(|| \"s\").unwrap_or(\"\")\n            );\n        }\n        Ok(kinds)\n    }\n}\n\n/// Patch is a dependency override that knows where it has been defined.\n/// See [`PatchLocation`] for possible locations.\n#[derive(Clone, Debug)]\npub struct Patch {\n    pub dep: Dependency,\n    pub loc: PatchLocation,\n}\n\n/// Place where a [`Patch`] has been defined.","sourceCodeStart":651,"sourceCodeEnd":687,"githubUrl":"https://github.com/rust-lang/cargo/blob/98a09e7e7d62850f14e5b6132101fc1edd19a16f/src/workspace/dependency.rs#L651-L687","documentation":"Thrown by ArtifactKind::validate() when parsing a list of artifact specifiers (e.g. for cargo artifact selection). After collecting all kinds, it sorts and dedups them; if the original list had more entries than the deduped list, duplicates were present. The count and pluralization are interpolated into the message. This guards the Artifact::parse entry point used when a caller passes a slice of artifact strings like ['bin','cdylib','bin'].","triggerScenarios":"Calling Artifact::parse (or a higher-level API forwarding an artifact list) with a list containing the same specifier more than once, e.g. ['cdylib','cdylib'] or ['bin:foo','bin:foo']. Each string is parsed via ArtifactKind::parse and the resulting Vec is passed to ArtifactKind::validate, which detects the size mismatch after sort+dedup.","commonSituations":"A build tool or cargo subcommand forwards user-supplied --artifact flags into a list and the user repeated one. Script-generated artifact lists that append rather than replace. Aliasing bugs where two CLI flags collapse to the same ArtifactKind.","solutions":["Remove the duplicate specifier from the artifact list before calling Artifact::parse.","If building the list programmatically, dedup the input strings (or the parsed ArtifactKind values) before validation.","If the duplicate is unintentional from CLI parsing, audit how repeated flags are collected (append vs overwrite)."],"exampleFix":"// before\nlet artifacts = vec![\"cdylib\", \"cdylib\", \"staticlib\"];\nlet art = Artifact::parse(&artifacts, true, None, false)?; // errors\n\n// after\nlet artifacts = vec![\"cdylib\", \"staticlib\"];\nlet art = Artifact::parse(&artifacts, true, None, false)?;","handlingStrategy":"validation","validationCode":"fn dedup_artifacts(specs: &[String]) -> Vec<String> {\n    let mut seen = std::collections::HashSet::new();\n    let mut out = Vec::new();\n    for s in specs {\n        if seen.insert(s.clone()) { out.push(s.clone()); }\n    }\n    out\n}\n// call before Artifact::parse\nlet clean = dedup_artifacts(&user_artifacts);\nlet artifact = Artifact::parse(&clean, is_lib, target, unstable)?;","typeGuard":"fn has_duplicate_artifacts(specs: &[impl AsRef<str>]) -> bool {\n    let mut seen = std::collections::HashSet::new();\n    specs.iter().any(|s| !seen.insert(s.as_ref().to_owned()))\n}","tryCatchPattern":"match Artifact::parse(&artifacts, is_lib, target, unstable) {\n    Ok(a) => a,\n    Err(e) if e.to_string().contains(\"duplicate binary artifact\") => {\n        // dedup and retry once\n        let deduped: Vec<_> = artifacts.iter().collect::<HashSet<_>>().into_iter().collect();\n        Artifact::parse(&deduped, is_lib, target, unstable)?\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always dedup user-supplied artifact lists before passing to Artifact::parse.","Use a HashSet when collecting artifact flags from repeated CLI args.","Log the raw artifact list when validation fails to surface the duplicate quickly."],"tags":["cargo","artifacts","manifest","validation","duplicate"],"backgroundTag":null,"analyzedSha":"98a09e7e7d62850f14e5b6132101fc1edd19a16f","analyzedAt":"2026-08-11T17:42:36.556Z","contentChangedAt":"2026-08-11T17:42:36.556Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}