rust-lang/cargo · error

cannot specify both recursive and precise simultaneously

Error message

cannot specify both recursive and precise simultaneously

What it means

Thrown by `cargo update` when both `--recursive` and `--precise <version>` are passed simultaneously. These flags are mutually exclusive: `--recursive` upgrades an entire dependency subtree, while `--precise` pins a single package to an exact version. Combining them is semantically contradictory.

Solutions

  1. Use `--precise` alone to pin one package: `cargo update --precise 1.2.3 <pkg>`.
  2. Use `--recursive` alone to upgrade a full subtree: `cargo update --recursive <pkg>`.
  3. Remove one of the two conflicting flags from the command.

Example fix

# Before
cargo update --recursive --precise 1.2.3 serde

# After — choose one
cargo update --precise 1.2.3 serde
# or
cargo update --recursive serde
Defensive patterns

Strategy: validation

Validate before calling

fn validate_update_opts(recursive: bool, precise: Option<&str>) -> Result<(), String> {
    if recursive && precise.is_some() {
        return Err("cannot use --recursive and --precise together".into());
    }
    Ok(())
}

Prevention

When it happens

Trigger: Running `cargo update --recursive --precise 1.2.3 <pkg>` or calling `update_lockfile` with `UpdateOptions` where both `recursive` is true and `precise` is `Some(...)`.

Common situations: Misunderstanding the flags; copy-pasting a command with both flags; scripting cargo update with incorrect option combinations.

Related errors


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

Appendix: source

Thrown at src/ops/cargo_update.rs:54

    let previous_resolve = None;
    let mut resolve = ops::resolve_with_previous(
        &mut registry,
        ws,
        &CliFeatures::new_all(true),
        HasDevUnits::Yes,
        previous_resolve,
        None,
        &[],
        true,
    )?;
    ops::write_pkg_lockfile(ws, &mut resolve)?;
    print_lockfile_changes(ws, previous_resolve, &resolve, &mut registry)?;
    Ok(())
}

pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoResult<()> {
    if opts.recursive && opts.precise.is_some() {
        anyhow::bail!("cannot specify both recursive and precise simultaneously")
    }

    if ws.members().count() == 0 {
        anyhow::bail!("you can't generate a lockfile for an empty workspace.")
    }

    // Updates often require a lot of modifications to the registry, so ensure
    // that we're synchronized against other Cargos.
    let _lock = ws
        .gctx()
        .acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;

    let previous_resolve = match ops::load_pkg_lockfile(ws)? {
        Some(resolve) => resolve,
        None => {
            match opts.precise {
                None => return generate_lockfile(ws),

View on GitHub (pinned to 98a09e7e7d)