pola-rs/polars · error

should be hashable

Error message

should be hashable

What it means

ObjectValue wraps an arbitrary Python object stored in an Object-dtype column. Its Hash implementation calls Python's hash() on the wrapped value; if that value is unhashable (dict, list, set — anything with __hash__ = None), the Python call fails and this expect panics with 'should be hashable'.

Source

Thrown at crates/polars-python/src/conversion/mod.rs:753

}

#[derive(Debug)]
#[repr(transparent)]
pub struct ObjectValue {
    pub inner: Py<PyAny>,
}

impl Clone for ObjectValue {
    fn clone(&self) -> Self {
        Python::attach(|py| Self {
            inner: self.inner.clone_ref(py),
        })
    }
}

impl Hash for ObjectValue {
    fn hash<H: Hasher>(&self, state: &mut H) {
        let h = Python::attach(|py| self.inner.bind(py).hash().expect("should be hashable"));
        state.write_isize(h)
    }
}

impl Eq for ObjectValue {}

impl PartialEq for ObjectValue {
    fn eq(&self, other: &Self) -> bool {
        Python::attach(|py| {
            match self
                .inner
                .bind(py)
                .rich_compare(other.inner.bind(py), CompareOp::Eq)
            {
                Ok(result) => result.is_truthy().unwrap(),
                Err(_) => false,
            }
        })

View on GitHub (pinned to df599052da)

Solutions

  1. Cast the Object column to String (e.g. via map to repr/json) before group_by/unique/join
  2. If using custom classes, define both __eq__ and __hash__ consistently
  3. Avoid storing unhashable values in Object columns destined for key-based operations
  4. Use a struct column instead of objects when the data is record-shaped

Example fix

# before
(df.group_by(pl.col("obj")).agg(pl.len()))  # obj holds dicts -> panic 'should be hashable'

# after
df.group_by(pl.col("obj").map_elements(lambda v: repr(v), return_dtype=pl.String)).agg(pl.len())

# or on the class side
class Key:
    def __init__(self, v): self.v = v
    def __eq__(self, o): return isinstance(o, Key) and o.v == self.v
    def __hash__(self): return hash(self.v)
Defensive patterns

Strategy: type-guard

Validate before calling

# Python: verify object column is hashable before hash-based ops
def column_is_hashable(s: pl.Series) -> bool:
    return all(is_hashable(v) for v in s.head(100).to_list())

from collections.abc import Hashable
def is_hashable(v) -> bool:
    try:
        hash(v)
        return True
    except TypeError:
        return False

Type guard

def is_hashable(v) -> bool:
    try:
        hash(v); return True
    except TypeError:
        return False

Prevention

When it happens

Trigger: Any hash-based operation on an Object column containing unhashable Python values: group_by, unique/n_unique, joins on that column, is_duplicated, value_counts.

Common situations: Columns built from Python dicts/lists/objects (e.g. via apply returning complex values) then used as group-by or join keys; user classes that define __eq__ without __hash__ (Python then sets __hash__ to None).

Related errors


AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16). Data as JSON: /api/errors/c2c5fbcc8f19fa5b. Report an issue: GitHub.