I had three PRs open against tracel-ai/burn and none of them were moving. The natural assumption is that something is wrong with the change: a failing test, a review I hadn’t answered, a design the maintainers didn’t want.
It turned out to be none of those. The reason two of them could not merge had
nothing to do with the code in the diff — the required CI check they depend on
was already failing on main, before my branches existed.
This is how I found that out, and how a one-line lockfile change unblocked every open PR in the repository.
What “mergeable: blocked” means
GitHub shows mergeable_state: blocked when a PR can’t merge, but it doesn’t say
why. The why lives in the repository’s branch ruleset. Burn requires one
approving review and a fixed set of status checks, including the Windows test
jobs. If any of those checks isn’t green, the PR stays blocked no matter how
correct the code is.
So the first thing I did was stop guessing and enumerate: list the required check names from the ruleset, then list the actual check runs on each PR’s head commit. For the Bluestein FFT PR (#5757), all fourteen required checks were green — its only blocker was that no human had approved it. For the other two, the Windows checks were failing.
The failure was inside a dependency
The failing job’s log ended with an error that had nothing to do with my diff:
error[E0308]: mismatched types
error[E0277]: the trait bound `ResourceCategory: From<&D3D12_RESOURCE_DESC>` is not satisfied
error[E0277]: the trait bound `&ID3D12Heap: Param<ID3D12Heap, InterfaceType>` is not satisfied
error: could not compile `wgpu-hal` (lib) due to 10 previous errors
wgpu-hal is not my code; it’s a graphics dependency of Burn. The compiler was
seeing an ID3D12Device from one crate and a Direct3D12::ID3D12Device from
another — the same type, from two different versions of the same crate.
Two versions of windows
The windows crate is versioned in a way that makes different minor versions
incompatible, so mixing them produces exactly this kind of type mismatch.
wgpu-hal builds against windows 0.62.2. gpu-allocator — which wgpu-hal
calls into on Windows — had been resolved to windows 0.61.3.
gpu-allocator’s own requirement allows versions up to 0.62, so its resolution
isn’t wrong in isolation. What happened is that a cubecl/cubek dependency bump
(#5854) caused Cargo to re-resolve the windows graph, and it chose to unify
gpu-allocator onto 0.61.3 to share a version with another crate that needs that
exact line. That saved one duplicate crate and broke the DX12 backend.
This is a recurring pattern in the repository: the same class of breakage had
already been fixed once in #5735 after an earlier cube update, and the newer bump
reintroduced it. When the lockfile is the bug, it reproduces identically for
everyone — which is why the failure was red on main, not just on my branch.
The fix
One line in Cargo.lock: give gpu-allocator back the windows version
wgpu-hal actually passes it.
The important part is proving that line is sufficient. I cross-checked the exact unit CI fails on, without needing a Windows machine:
cargo check -p wgpu-hal --target x86_64-pc-windows-msvc --locked
Against main’s lockfile it produces the same ten errors. With the one-line
change it finishes clean. I also stashed the change and re-ran it to confirm the
errors come back — otherwise “it compiles” could be true for the wrong reason.
I sent it as a standalone dependency fix, #5867, rather than bundling it into the feature PRs: unrelated lockfile churn inside a feature diff is exactly the kind of thing a reviewer rejects.
What I’d check first next time
The lesson isn’t “dependency bumps are scary”. It’s about where to look when a PR stalls:
- Check whether the required checks pass on
mainfirst. Ifmainis red, every open PR is red for reasons that have nothing to do with their changes, and no amount of testing your own diff will help. - Read
mergeable_state: blockedagainst the actual ruleset. “Blocked” is a verdict, not a diagnosis. The required-review count and the required-check list tell you which of the two is failing. - A CI error in a dependency is still a real bug — just not the one you were asked to fix. Reading the log to the crate name tells you whether it’s yours to own.
The instinct to assume “it must be my code” is usually right. But when a shared repository is moving under you, it’s worth checking whether the ground is broken before you doubt the code.