rust-lang/cargo · error

multiple packages link to native library `{}`, but a native

Error message

multiple packages link to native library `{}`, but a native library can be linked only once

{}
links to native library `{}`

{}
also links to native library `{}`

What it means

Cargo enforces that the `package.links` manifest key is unique across the resolved dependency graph: each native library name may be linked by at most one crate. validate_links (links.rs:21-60) walks the unit graph; when a second package declares the same `links` value, it bails with a message listing both packages and their dependency paths to the top-level crate. The constraint exists because two crates linking the same native library would cause duplicate-symbol / double-link errors at link time.

Source

Thrown at src/compiler/links.rs:44

    units.sort_unstable();
    for unit in units {
        if !validated.insert(unit.pkg.package_id()) {
            continue;
        }
        let Some(lib) = unit.pkg.manifest().links() else {
            continue;
        };
        if let Some(&prev) = links.get(lib) {
            let prev_path = resolve
                .path_to_top(&prev)
                .into_iter()
                .map(|(p, d)| (p, d.and_then(|d| d.iter().next())));
            let pkg = unit.pkg.package_id();
            let path = resolve
                .path_to_top(&pkg)
                .into_iter()
                .map(|(p, d)| (p, d.and_then(|d| d.iter().next())));
            anyhow::bail!(
                "multiple packages link to native library `{}`, \
                 but a native library can be linked only once\n\
                 \n\
                 {}\nlinks to native library `{}`\n\
                 \n\
                 {}\nalso links to native library `{}`",
                lib,
                describe_path(prev_path),
                lib,
                describe_path(path),
                lib
            )
        }
        links.insert(lib.to_string(), unit.pkg.package_id());
    }
    Ok(())
}

View on GitHub (pinned to 0e07a15537)

Solutions

  1. Run `cargo tree` and locate the two crates sharing the `links` name; pick one and exclude/replace the other.
  2. Use `[patch]` or `[replace]` to collapse both onto a single version of the native-binding crate.
  3. If you own one of the crates, remove its `links` key if it does not actually need to claim the native library.
  4. Upgrade/downgrade one crate to a version that does not collide (check the crate's changelog for `links` changes).

Example fix

# before - two crates link `zlib`
# Cargo.toml of crate A: links = "zlib"
# Cargo.toml of crate B: links = "zlib"
# after - patch to a single source of zlib binding
[patch.crates-io]
flate2 = { git = 'https://...single-zlib-binding' }
Defensive patterns

Strategy: validation

Validate before calling

# In CI, assert no duplicate links before building:
cargo tree -e normal --prefix none | grep -i 'links' || true
# Or a pre-build check script that scans Cargo.toml files:
# rg '^links\s*=' --type toml

Prevention

When it happens

Trigger: Two dependencies in the resolved graph both set `links = "foo"` in their Cargo.toml. Occurs during dependency resolution / build unit graph validation, before compilation. Common when two crates bind the same C library (e.g. two openssl bindings, two zlib bindings).

Common situations: Pulling in both `openssl-sys` and another crate that also links openssl; duplicate vendored copies of a native lib through different dependency versions; an older crate still carrying a `links` key that collides with a newer one.

Related errors


AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06). Data as JSON: /data/errors/26dde2830d29878f.json. Report an issue: GitHub.