From 3fe5f0179220dc8f27a1454e701b1cf49e878770 Mon Sep 17 00:00:00 2001 From: Bas Zalmstra <4995967+baszalmstra@users.noreply.github.com> Date: Wed, 3 Jun 2026 16:56:01 +0200 Subject: [PATCH] fix: don't merge conflict nodes with distinct requirements Versions of a package that require different versions of a missing dependency are no longer collapsed into a single node in the conflict report. Previously only one of those requirements was shown and the rest were hidden, producing a misleading error message. See conda/rattler#2476. --- src/conflict.rs | 6 ++++-- tests/solver/main.rs | 14 ++++++++++++++ ..._unsat_no_candidates_distinct_requirements.snap | 11 +++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 tests/solver/snapshots/solver__unsat_no_candidates_distinct_requirements.snap diff --git a/src/conflict.rs b/src/conflict.rs index 32d22c4b..e363313b 100644 --- a/src/conflict.rs +++ b/src/conflict.rs @@ -440,14 +440,16 @@ impl ConflictGraph { | ConflictNode::Excluded(_) => continue, }; + // Candidates that require different version sets stay separate so each + // distinct requirement is reported to the user (conda/rattler#2476). let predecessors: Vec<_> = graph .edges_directed(node_id, Direction::Incoming) - .map(|e| e.source()) + .map(|e| (e.weight().try_requires(), e.source())) .sorted_unstable() .collect(); let successors: Vec<_> = graph .edges(node_id) - .map(|e| e.target()) + .map(|e| (e.weight().try_requires(), e.target())) .sorted_unstable() .collect(); diff --git a/tests/solver/main.rs b/tests/solver/main.rs index a1d16f8d..856e281c 100644 --- a/tests/solver/main.rs +++ b/tests/solver/main.rs @@ -450,6 +450,20 @@ fn test_unsat_no_candidates_for_child_2() { insta::assert_snapshot!(error); } +// Versions requiring different versions of a missing dependency are each +// reported (conda/rattler#2476). +#[test] +fn test_unsat_no_candidates_distinct_requirements() { + let provider = BundleBoxProvider::from_packages(&[ + ("a", 1, vec!["b 41..42"]), + ("a", 2, vec!["b 41..42"]), + ("a", 3, vec!["b 42..43"]), + ("a", 4, vec!["b 43..44"]), + ]); + let error = solve_unsat(provider, &["a"]); + insta::assert_snapshot!(error); +} + #[test] fn test_unsat_missing_top_level_dep_1() { let provider = BundleBoxProvider::from_packages(&[("asdf", 1, vec![])]); diff --git a/tests/solver/snapshots/solver__unsat_no_candidates_distinct_requirements.snap b/tests/solver/snapshots/solver__unsat_no_candidates_distinct_requirements.snap new file mode 100644 index 00000000..877b2f04 --- /dev/null +++ b/tests/solver/snapshots/solver__unsat_no_candidates_distinct_requirements.snap @@ -0,0 +1,11 @@ +--- +source: tests/solver/main.rs +expression: error +--- +a * cannot be installed because there are no viable options: +├─ a 4 would require +│ └─ b >=43, <44, for which no candidates were found. +├─ a 3 would require +│ └─ b >=42, <43, for which no candidates were found. +└─ a 1 | 2 would require + └─ b >=41, <42, for which no candidates were found.