PSA: test with minimal versions, because your deps are most likely all broken

I’ve tried to verify whether I specify correct versions of my crates, and quickly found that version requirements everywhere are totally broken. Plenty of crates actually implictly depend on latest versions, and not the versions they specify as their dependencies!

rm Cargo.lock; 
cargo +nightly build -Z minimal-versions

e.g. I’ve ended up with a combination of crates that dug back to winapi-0.0.1! It doesn’t compile, because it depended on pre-Rust-1.0 built-in libc crate. It’s a blast from the past.

So hey, bump those versions! If a crate is at 0.1.257 now, chances are that 0.1 version requirement will pick up some some dinosaurs.

4 Likes

Share this sentiment. If your library crate specifies:

[package]
name = "my_lib"

[dependencies]
theirs = "0.1"

If theirs updates to 0.1.10 with a bug fix, and you pick it up locally using cargo update and publish a release, everyone else who cloned and built your crate before theirs was updated still has to run cargo update. However if you updated Cargo.toml to use theirs = "0.1.10", then they receive that transitive bug fix immediately.

It does feel annoying when people say "the fix is to run cargo update", when really it should be "bump the version dependency in Cargo.toml". Because dependency = "0.1.10" is interpreted as dependency = "^0.1.10" (docs).

I’d recommend an alternative not involve deleting the lock file:

cargo +nightly update -Z minimal-versions
cargo build
cargo test

Still, this is a good idea. I never supported adding patch version minimums before we had cargo update -Z minimal-versions, but it makes sense now that we can actually test to ensure we have good support.

your deps are most likely all broken

I think this a slight exaggeration. It’s true that most lower bounds are invalid, and it does cause some problems in practice, but not too much actually.

It is unclear if efforts to test this (+1 CI job basically) are worth the actual benefit.

OTOH, --minimal-version in theory is good way to check your crate against MSRV: because you use minimal versions, your build won’t break when you dependency publish a semver-compatible update which bumps MSRV.

1 Like

There seems to be an all too common, but IMO overly pessimistic, view that since things break ("your deps are broken") when first testing with -Z minimal-versions, and that its too fragile for CI, that therefore its not worth the effort.

On the contrary I think its a highly valuable as a (manual) exercise to improve any MAJOR or MINOR release during staging. When I take the time to do it, I almost always learn something that improves the release and makes it more likely and less problematic that my consumers can do the same. This includes, perhaps counter-intuitively, the ability to shore up broken (wrong or unspecified minimum) transitive dependencies. For example the following PR shows an instance of my manual process:

Which lead me to:

A min transitive dependency constraint for my body-image-futio-2.1.0 and barc-2.0.0 releases.

Also since I'm in the unpopular position of having to implement constraints on transitive deps in order to uphold my MSRV guarantees for older PATCH releases, this is another case where carefully specifying minimum dependencies avoids surprising outcomes on cargo update. See Rust version requirement change as semver breaking or not (post).

Finally, in case someone might think I'm wasting time on theoretical concerns with minimum versions: If you are in the position of bisecting a bug that spans crate releases, backporting fixes, or conservatively applying PATCH releases (hopefully fixes only) to an application with an (old) lockfile, this testing and the above described mitigations are critical in the real world!

BTW: I wish I didn't have to switch to nightly to use -Z minimal-versions. Why isn't it a stable feature of cargo? Seems like this might be a case of the perfect being an enemy of the good.

2 Likes