rust-lang/cargo · error

can't specify both lib and binary outputs

Error message

can't specify both lib and binary outputs

What it means

`cargo new`/`cargo init` accepts `--lib` or `--bin` to force the project kind, but passing both is contradictory — a single new project cannot be declared as both a library and a binary template at creation. The `(bin, lib) == (true, true)` arm of the match bails immediately before touching the filesystem.

Solutions

  1. Pass only one of `--lib` or `--bin` — for a library use `--lib`, for a binary use `--bin` (or omit both to auto-detect).
  2. For a project that needs both a lib and a bin, create as `--bin` then add a `src/lib.rs` / `[[lib]]` target, or create `--lib` and add a `src/main.rs`.
  3. Fix shell aliases / wrappers that inject both flags.

Example fix

# before
$ cargo new --lib --bin myproject   # error

# after
$ cargo new --bin myproject   # then later add src/lib.rs if a lib is also needed
$ cargo new --lib myproject   # or start as a library
Defensive patterns

Strategy: validation

Validate before calling

fn resolve_kind(bin: bool, lib: bool) -> Result<Kind, String> {
    match (bin, lib) {
        (true, true) => Err("pass at most one of --bin/--lib".into()),
        (false, true) => Ok(Kind::Lib),
        _ => Ok(Kind::Bin),
    }
}

Type guard

fn exactly_one_kind_flag(bin: bool, lib: bool) -> bool { bin ^ lib }

Prevention

When it happens

Trigger: Running `cargo new --lib --bin myproject` or `cargo init --lib --bin`. Programmatic callers of `NewOptions::new` passing both `bin: true` and `lib: true`.

Common situations: Aliases or shell wrappers that always add `--bin` colliding with an explicit `--lib`. Copy-pasting flags from two different tutorials. Build scripts that combine flags from multiple sources without deduping.

Related errors


AI-assisted analysis of rust-lang/cargo@98a09e7e7d (2026-08-11). Data as JSON: /api/errors/aa8d2f9c3efdf1e2. Report an issue: GitHub.

Appendix: source

Thrown at src/ops/cargo_new.rs:80

    source_files: Vec<SourceFileInformation>,
    edition: Option<&'a str>,
    registry: Option<&'a str>,
}

impl NewOptions {
    pub fn new(
        version_control: Option<VersionControl>,
        bin: bool,
        lib: bool,
        path: PathBuf,
        name: Option<String>,
        edition: Option<String>,
        registry: Option<String>,
    ) -> CargoResult<NewOptions> {
        let auto_detect_kind = !bin && !lib;

        let kind = match (bin, lib) {
            (true, true) => anyhow::bail!("can't specify both lib and binary outputs"),
            (false, true) => NewProjectKind::Lib,
            (_, false) => NewProjectKind::Bin,
        };

        let opts = NewOptions {
            version_control,
            kind,
            auto_detect_kind,
            path,
            name,
            edition,
            registry,
        };
        Ok(opts)
    }
}

fn get_name<'a>(path: &'a Path, opts: &'a NewOptions) -> CargoResult<&'a str> {

View on GitHub (pinned to 98a09e7e7d)