In a brand new, 2024-edition Cargo project, add version 0.9.0 of mitsein as a dependency. mitsein has arrayvec listed as an optional dependency, and there is an explicit "arrayvec" feature (disabled by default) that uses it. As you'd expect, because the "arrayvec" feature is not enabled, arrayvec is not listed in Cargo.lock, and it is not listed under the "resolve" key in cargo metadata's output. However, if you then enable the "serde" feature of mitsein, which declares a dependency on "arrayvec?/serde" , then arrayvec will appear in Cargo.lock and in the "resolve" section of cargo metadata even though it's still not actually used by anything (and cargo tree -i arrayvec even fails to find it).
Is this intentional behavior on Cargo's part? I couldn't find any related issues on GitHub. If this is intentional, is there a simple or straightforward way to filter arrayvec and other similarly unused dependencies out of cargo metadata?
kpreid
January 10, 2026, 4:39pm
2
Sounds unintentional to me. I’d file a bug.
Bug already filed:
opened 05:31PM - 30 Jun 22 UTC
C-bug
S-needs-design
Command-vendor
A-lockfile
A-features2
### Problem
Lets say I have two crates, with these contents of `Cargo.toml`. … The Rust code does not matter here.
```toml
# foo/Cargo.toml
[dependencies]
serde = {version = "1.0.133", optional = true, default-features = false}
time = {version = "=0.3.10", optional = true, default-features = false}
chrono = {version = "=0.4.18", optional = true, default-features = false}
[features]
serialization = ["dep:serde", "time?/serde-well-known"]
```
```toml
# bar/Cargo.toml
[dependencies]
foo.features = ["serialization"]
foo.path = "../foo"
# time = "=0.3.11"
# chrono = "=0.4.19"
```
As you can see, `bar` depends on `foo` and enables the `serialization` feature, but it does not enable the `time` nor the `chrono` feature.
This results in the following `bar/Cargo.lock` file:
<details>
<summary><code>bar/Cargo.lock</code></summary>
```toml
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "app"
version = "0.1.0"
dependencies = [
"foo",
]
[[package]]
name = "foo"
version = "0.1.0"
dependencies = [
"serde",
"time",
]
[[package]]
name = "itoa"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
[[package]]
name = "libc"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]]
name = "num_threads"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
dependencies = [
"libc",
]
[[package]]
name = "serde"
version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
[[package]]
name = "time"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82501a4c1c0330d640a6e176a3d6a204f5ec5237aca029029d21864a902e27b0"
dependencies = [
"itoa",
"libc",
"num_threads",
"serde",
]
```
</details>
The relevant snippet is at the end:
```toml
[[package]]
name = "time"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82501a4c1c0330d640a6e176a3d6a204f5ec5237aca029029d21864a902e27b0"
dependencies = [
"itoa",
"libc",
"num_threads",
"serde",
]
```
Here the dependency `time` is declared, even though it is an optional dependency and nothing enabled the corresponding feature on `foo`. The `time` dependency even has `serde` listed as one of its dependencies too.
---
I think this is problematic in a couple of ways.
It bloats the `Cargo.lock` and makes it imply that changes are larger than they actually are. In the above example adding `foo` will also add `time` even if that is not necessary.
Dependency management tools will get confused by this. I mean tools like dependabot or `cargo audit`, which use the `Cargo.lock` as source of truth. Since these tools will see an entry for `time`, even if it is unused, they will create pull requests or warn about security vulnerabilities which *do not exists*.
This prevents using two crates with conflicting version requirements. You can see what happens if you uncomment the lines in `bar/Cargo.toml`.
Uncommenting `time` will fail, since now two conflicting version constraints (`=0.3.10` != `=0.3.11`) exist.
However, uncommenting `chrono` **works** with the conflicting versions (`=0.4.18` != `=0.4.19`).
### Steps
1. Create project `foo` with the above content for `Cargo.toml`.
2. Create project `bar` with the above content for `Cargo.toml`.
3. Observe how the `Cargo.lock` of `bar` contains an entry for `time` and even a transitive `serde` dependency in `time`.
### Possible Solution(s)
Disabled optional dependencies should not be tracked in `Cargo.lock`, even if there is a weak dependency linking to it. This brings it in line with "normal" optional dependencies.
### Notes
While the `time` entry exists in the `Cargo.lock`, it appears cargo correctly ignores it when building the code. There is neither a `Compiling time ...` log line nor are there any artifacts in the `target` folder associated with `time`.
I checked various issues and documentation entries, but I couldn't find if this is a bug or intended.
The tracking issue (<https://github.com/rust-lang/cargo/issues/8832>) and documentation (<https://doc.rust-lang.org/nightly/cargo/reference/features.html#dependency-features>) do not mention any changes in to `Cargo.lock`. Neither does the implementation PR (<https://github.com/rust-lang/cargo/pull/8818>), which does not even seem to have any lock files.
### Version
```text
cargo 1.62.0 (a748cf5a3 2022-06-08)
release: 1.62.0
commit-hash: a748cf5a3e666bc2dcdf54f37adef8ef22196452
commit-date: 2022-06-08
host: x86_64-unknown-linux-gnu
libgit2: 1.4.2 (sys:0.14.2 vendored)
libcurl: 7.80.0-DEV (sys:0.4.51+curl-7.80.0 vendored ssl:OpenSSL/1.1.1n)
os: OracleLinux 36.0.0 [64-bit]
FYI: My OS is Fedora 36, but this is the output of `cargo version --verbose`.
```
6 Likes