Desk Clarity

A field guide to everyday digital problems.

Developer tools / Practical guide

Python Heapq Cannot Compare Dictionaries at Equal Priority: Add a Unique Tie Breaker

A heap accepts the first task but raises TypeError when another dictionary has the same priority.

By ON Lab2 min readSources checked November 10, 2026 (KST)

Heap tuples compare later fields when earlier fields tie. Store a unique sequence number between priority and payload so equal priorities never force a comparison between dictionaries.

Check the failure with a small fixture

A heap accepts the first task but raises TypeError when another dictionary has the same priority.

import heapq
from itertools import count
bad = []
heapq.heappush(bad, (5, {"job": "one"}))
try:
    heapq.heappush(bad, (5, {"job": "two"}))
except TypeError:
    print("payload comparison reached")
# Start fresh: a failed insertion is not a transaction rollback.
heap, sequence = [], count()
for name in ["one", "two", "three"]:
    heapq.heappush(heap, (5, next(sequence), {"job": name}))
assert [heapq.heappop(heap)[2]["job"] for _ in range(3)] == ["one", "two", "three"]

What the result means

The second push reaches the dictionaries because both priority values are 5. In the corrected heap, a distinct counter decides every equal-priority comparison before the payload field is reached. The counter also preserves arrival order among equal priorities, which plain heap ordering does not otherwise promise.

Choose the correction for your caller

Keep the sequence unique across the active heap. Do not reset the counter while older entries remain unless another guaranteed unique key exists. If payloads should never participate in ordering, an ordered dataclass with a non-comparing payload is another design, but decide separately whether equal-priority stability matters. Avoid mutating priority fields inside existing entries: replace entries through a planned update scheme and preserve the heap invariant.

Limits and the next check

A failed heap push can have modified the list before comparison fails, so the fixture discards that heap. Numeric priority policy, cancellation, concurrency and persistence are separate concerns. heapq is a min-heap by default; the smallest priority is retrieved first.

Related: Compare a related data or execution contract.

The embedded Python example was executed as an isolated local script on November 10, 2026 (KST), using Python 3.11.6. It demonstrates the stated boundary; it is not a test of your application or a promise of compatibility with every Python release.

Sources & further reading