Conversation
…print hash_sequence, hash_mapping, and hash_set hashed the literal "<unhashable>" sentinel like any other value instead of propagating it, so two objects differing only below MAX_DEPTH (or containing an unfingerprintable type) got the same normal-looking hash and the caching adapter's UNHASHABLE guard never fired.
|
@AmirF194 mind fixing the pre-commit checks -- you should be able to run |
Running 'uv run prek run --all-files --hook-stage pre-merge-commit' (per the repo's Static Checks CI step) flags two files under ui/backend/server/tests/ that were already out of sync with the pinned ruff formatter on main, unrelated to the fingerprinting change in this PR. Applying 'ruff format' fixes it; no behavior change, whitespace/line-wrap only.
|
Thanks for the pointer. Ran The Unit Tests failures across 3.10 through 3.14 are a separate, pre-existing issue: they are pandas/polars API drift (dtype naming, removed kwargs like |
hash_value's depth-limited default case returns the literal string<unhashable>once it can't recurse further, buthash_sequence,hash_mapping, andhash_setwere hashing that string like any other value instead of treating it specially. Two objects that differ only belowMAX_DEPTH, or that contain a type with no registered fingerprint (torch.Tensor, per the follow-up comment), end up with the same normal-looking hash. The cache adapter'sdata_version == fingerprinting.UNHASHABLEguard never fires on that hash, so it gets treated as a real, stable fingerprint and the cache serves a stale result instead of re-executing.Fixed by propagating the sentinel up: if any element, key, or value inside a sequence/mapping/set comes back
UNHASHABLE, the container now returnsUNHASHABLEtoo, all the way to the top. That's the only change; the three call sites inadapter.pythat already check for the sentinel don't need to move.Ran your script from the issue against HEAD:
weight=1.0andweight=2.0both hashed to the same value and both returned the10.0prediction before the fix. After it, both return<unhashable>, so caching correctly refuses to reuse the cached result. I didn't independently run the torch.Tensor example from the follow-up comment (no torch in this environment), but it hits the exact same propagation path: any valuehash_valuecan't fingerprint now bubbles up instead of getting silently absorbed into a parent hash.Added one test with a plain nested-object chain that reproduces the collision (no torch needed), plus a direct test per container type, since sequence/mapping/set each had their own copy of the bug.
Fixes #1715