{"id":"8d38e082f73ec34f","repo":"rust-lang/cargo","slug":"cannot-have-a-package-with-multiple-libraries-fou","errorCode":null,"errorMessage":"cannot have a package with multiple libraries, found both `{}` and `{}`","messagePattern":"cannot have a package with multiple libraries, found both `(.+?)` and `(.+?)`","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/ops/cargo_new.rs","lineNumber":406,"sourceCode":"    let mut duplicates_checker: BTreeMap<&str, &SourceFileInformation> = BTreeMap::new();\n\n    for i in detected_files {\n        if i.bin {\n            if let Some(x) = BTreeMap::get::<str>(&duplicates_checker, &name) {\n                anyhow::bail!(\n                    \"\\\nmultiple possible binary sources found:\n  {}\n  {}\ncannot automatically generate Cargo.toml as the main target would be ambiguous\",\n                    &x.relative_path,\n                    &i.relative_path\n                );\n            }\n            duplicates_checker.insert(name, i);\n        } else {\n            if let Some(plp) = previous_lib_relpath {\n                anyhow::bail!(\n                    \"cannot have a package with \\\n                     multiple libraries, \\\n                     found both `{}` and `{}`\",\n                    plp,\n                    i.relative_path\n                )\n            }\n            previous_lib_relpath = Some(&i.relative_path);\n        }\n    }\n\n    Ok(())\n}\n\nfn plan_new_source_file(bin: bool) -> SourceFileInformation {\n    if bin {\n        SourceFileInformation {\n            relative_path: \"src/main.rs\".to_string(),","sourceCodeStart":388,"sourceCodeEnd":424,"githubUrl":"https://github.com/rust-lang/cargo/blob/0e07a155371a6ce88ae53a2c00df940280c09a67/src/ops/cargo_new.rs#L388-L424","documentation":"During `cargo init`, when DetectSourcePaths finds two files that are both classified as library roots (e.g. src/lib.rs AND src/<name>.rs), Cargo refuses because a package can have only one library target. previous_lib_relpath at cargo_new.rs:405 is already set when the second lib file is seen, so it bails naming both paths.","triggerScenarios":"Run `cargo init` in a directory containing both `src/lib.rs` and `src/<pkgname>.rs` (the per-name lib candidate), or two files that do not contain `fn main` and are thus detected as libraries.","commonSituations":"Pre-existing source tree with a src/lib.rs plus a sibling module file at src/<crate>.rs that Cargo's heuristic interprets as another lib; migration of a project that uses the 2015-era module layout; leftover stub files.","solutions":["Keep only one library root (typically src/lib.rs); move or delete the duplicate","If the second file is a module, move it under src/ as a submodule (e.g. src/foo/mod.rs) so it is not mistaken for a crate root","Manually author Cargo.toml with an explicit [lib] section instead of relying on `cargo init` detection"],"exampleFix":"# before: src/lib.rs and src/myapp.rs both present\ncargo init\n# after\nmv src/myapp.rs src/myapp/mod.rs   # treat as module\ncargo init","handlingStrategy":"validation","validationCode":"use std::path::Path;\nfn count_lib_roots(dir: &Path, pkg_name: &str) -> usize {\n    let mut n = 0;\n    if dir.join(\"src/lib.rs\").is_file() { n += 1; }\n    if dir.join(format!(\"src/{pkg_name}.rs\")).is_file() { n += 1; }\n    n\n}\n\nif count_lib_roots(dir, name) > 1 { /* ask user to keep one */ }","typeGuard":"import { existsSync } from 'fs';\nfunction hasSingleLibRoot(dir: string, name: string): boolean {\n  const a = existsSync(`${dir}/src/lib.rs`);\n  const b = existsSync(`${dir}/src/${name}.rs`);\n  return !(a && b);\n}","tryCatchPattern":null,"preventionTips":["Standardize on src/lib.rs as the only library root","Place additional modules under src/<module>/mod.rs, not as siblings","Run a pre-init filesystem check in scaffolding scripts"],"tags":["cargo-init","library-target","ambiguity","source-detection"],"analyzedSha":"0e07a155371a6ce88ae53a2c00df940280c09a67","analyzedAt":"2026-08-06T01:46:58.334Z","schemaVersion":2}