pydantic/monty · error
{} python values are not hashable
Error message
{} python values are not hashable What it means
Fallback panic in MontyObject::hash for any Python value type that has no defined hash (lists, dicts, sets, etc.), mirroring CPython's `unhashable type` behavior but as an unrecoverable Rust panic rather than a TypeError. The message names the offending type via type_name().
Source
Thrown at crates/monty-types/src/object.rs:642
}
}
Self::Float(f) => f.to_bits().hash(state),
Self::String(string) => string.hash(state),
Self::Bytes(bytes) => bytes.hash(state),
Self::Date(date) => date.hash(state),
Self::DateTime(datetime) => datetime.hash(state),
Self::Time(time) => time.hash(state),
Self::TimeDelta(delta) => delta.hash(state),
Self::TimeZone(timezone) => timezone.hash(state),
Self::Path(path) => path.hash(state),
Self::FileHandle(MontyFileHandle { path, mode, position }) => {
path.hash(state);
mode.as_str().hash(state);
position.hash(state);
}
Self::Type(t) => t.name().hash(state),
Self::Cycle(_, _) => panic!("cycle values are not hashable"),
_ => panic!("{} python values are not hashable", self.type_name()),
}
}
}
impl PartialEq for MontyObject {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Ellipsis, Self::Ellipsis) => true,
(Self::NotImplemented, Self::NotImplemented) => true,
(Self::None, Self::None) => true,
(Self::Bool(a), Self::Bool(b)) => a == b,
(Self::Int(a), Self::Int(b)) => a == b,
(Self::BigInt(a), Self::BigInt(b)) => a == b,
// Cross-compare Int and BigInt without allocating a temporary BigInt.
(Self::Int(a), Self::BigInt(b)) | (Self::BigInt(b), Self::Int(a)) => b.to_i64() == Some(*a),
// Use to_bits() for float comparison to be consistent with Hash
(Self::Float(a), Self::Float(b)) => a.to_bits() == b.to_bits(),
(Self::String(a), Self::String(b)) => a == b,View on GitHub (pinned to adc986b362)
Solutions
- Only hash hashable variants: check the type (e.g. matches!(v, MontyObject::Int(_) | MontyObject::Str(_), ...)) before hashing
- Use a total, structural hash you control (e.g. hash of repr/JSON) for containers instead of this method
- If a legitimate type hits this arm, add an explicit hash arm in crates/monty-types/src/object.rs for it
Example fix
// before
map.insert(unhashable_value, data); // panics: list python values are not hashable
// after
if is_hashable(&unhashable_value) {
map.insert(unhashable_value, data);
} else {
map.insert(repr(&unhashable_value), data);
} Defensive patterns
Strategy: validation
Validate before calling
fn is_hashable(v: &MontyObject) -> bool {
use MontyObject::*;
!matches!(v, List(_) | Dict(_) | Set(_) | Bytearray(_) | Cycle(_, _))
} Type guard
fn is_hashable(v: &MontyObject) -> bool {
use MontyObject::*;
matches!(v, None | Bool(_) | Int(_) | Float(_) | Str(_) | Bytes(_) | Tuple(_) | FrozenSet(_) | FileHandle(_) | Type(_))
} Try / catch
// panics, not Result — check hashability first
if is_hashable(&v) { map.insert(v, data); } else { map.insert(repr(&v), data); } Prevention
- Treat containers (list/dict/set) as unhashable exactly like CPython
- Key maps on primitives or repr strings when unsure
- When adding new MontyObject variants, add an explicit hash arm instead of relying on the `_` fallback
When it happens
Trigger: Calling hash()/hash_of on a MontyObject whose variant is an unhashable container or object — e.g. using a list or dict as a dict key or in a set in host-side code that invokes this hash implementation.
Common situations: Host code using MontyObject values as HashMap keys without filtering; converting host-side sets keyed by returned sandbox values; a missing match arm for a newly added type landing in the `_` catch-all.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- cycle values are not hashable
- gather commit frame id is not a GatherFuture
- gather item is not a Coroutine, ExternalFuture, or GatherFut
- Cannot get identity of Dereferenced object
- invalid ascii byte
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/81126dbbd886c464.
Report an issue: GitHub.