Version mismatch between serde/serde_derive?

I'm trying to compile criterion, which is failing with lots of errors like,

error[E0603]: module `private` is private
    --> /home/…/.cargo/registry/src/github.com-1ecc6299db9ec823/criterion-0.3.4/src/lib.rs:1564:5
     |
1564 |     sampling_mode: ActualSamplingMode,
     |     ^^^^^^^^^^^^^ private module
     |
note: the module `private` is defined here
    --> /home/…/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.123/src/lib.rs:277:5
     |
277  | use self::__private as private;
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^

The issue seems to be that Cargo.lock contains a lock for serde v1.0.123 and serde_derive v1.0.118. If I delete the lock file, everything compiles just fine (and the resulting new lock file locks serde_derive v1.0.123). What I am hung up on is… why is my original project locking v1.0.118? Both cargo tree & Cargo.lock seem to indicate that the only thing that depends on serde_derive is criterion, so it should have been a new dependency, and should have pulled the latest version? I also checked criterion, and they're not specifying an overly specific pin (and deleting the lock file & getting the latest v1.0.123 confirms that).

I tried deleting just the section of lock file that is,

[[package]]
name = "serde_derive"
version = "1.0.118"
# (plus the rest of this [[package]] item)

But cargo bench just re-adds that same version. I have no idea where it is picking 1.0.118 from, since the only reference to it I can find is the one above that I am deleting?

I also tried cargo update -p serde_derive, but that makes no changes. cargo update seems to work, but updates all the dependencies, and there are updates in other dependencies of mine that apparently cause breakage, so I'd like to avoid that.

Basically,

» ls
Cargo.lock  Cargo.lock.broken  Cargo.toml  src
± crit:master:/
» grep -r * -e '1\.0\.118'
Cargo.lock.broken:version = "1.0.118"
± crit:master:/
» cargo bench
[snip]
   Compiling serde v1.0.123
   Compiling serde_derive v1.0.118  # y tho
[snip]
   Compiling criterion v0.3.4
error[E0603]: module `export` is private
   --> /home/…/.cargo/registry/src/github.com-1ecc6299db9ec823/criterion-0.3.4/src/connection.rs:201:17
    |
201 | #[derive(Debug, Deserialize)]
    |                 ^^^^^^^^^^^ private module
    |
note: the module `export` is defined here
   --> /home/…/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.123/src/lib.rs:275:5
    |
275 | use self::__private as export;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0603]: module `private` is private
   --> /home/…/.cargo/registry/src/github.com-1ecc6299db9ec823/criterion-0.3.4/src/connection.rs:205:9
    |
205 |         value: f64,
    |         ^^^^^ private module

Where is cargo bench getting this version from?

A gist containing both the Cargo.lock and Cargo.toml. The only other real file I have in my minimal test case is src/lib.rs, which is empty.

Okay maybe I have a guess here now. The lock file also naturally contains locks for serde_derive's dependencies; in this case, syn & proc-macro2. It seems like the later version of serde_derive requires newer versions of those dependencies. I guess cargo's dependency solver, however, figures it can't pull in the newer serde_derive, b/c that would violate / update the locks in the lockfile for syn & proc-macro2? (and, that makes sense, I suppose.)

If I delete all three of serde_derive, syn, and proc-macro2 from the lockfile, then cargo bench will pull in the newer version of serde_derive.

Still, this seems like I am "doing it wrong". I presume still that cargo update is what I want, but I haven't figured out how to get that to work yet.

Edit: so, passing --aggressive works, in the sense that it's at least a more minimal update than a full redo of the lockfile. But it is still a bit more than minimal (e.g., it also updates quote, as it does the entire dependency subtree), so I still wonder what best practice here is?

I don't know why this happens, but I would avoid manually editing the lock file if completely deleting it and letting it rebuild works. It is meant to be used by Cargo, not the human. There have been times that I have had build issues in my IDE and on those few occasions deleting the lock file has worked.

For the record, when importing serde, I find it easier to avoid breaking things by specifying major releases (which should never have breaking changes) and using the crate's feature flags to avoid versions mismatches. That doesn't seem to be the issue here, but it's one fewer thing that I can screw up.

https://git.sr.ht/~jeffa/serial_int/tree/master/item/Cargo.toml#L22-25

Criterion made a mistake of relying on a private implementation detail of serde, and serde eventually changed its internals making it painfully apparent.

You need to update all of them to their latest versions to sort it out. cargo update should be enough.

If you need some other dependencies at specific versions, it's better to state that explicitly in your Cargo.toml than rely on the lockfile never changing. Cargo unifies dependency versions across the entire tree, so you can even add deps you don't use directly just to specify their exact versions.