Skip to content

Error (TypeError: cannot pickle 'function' object) thrown in st.cache_resource is confusing because we only mention that an object needs to be hashable but it actually must also be pickleable #1399

@MacroBull

Description

@MacroBull

Checklist

  • I have searched the existing issues for similar issues.
  • I added a very descriptive title to this issue.
  • I have provided sufficient information below to help reproduce this issue.

Summary

Instead of using Python’s hashing semantics, Streamlit attempts to serialize (pickle) function arguments to bytes and hashes those bytes, which leads to surprising and misleading UnhashableParamErrors.

This behavior conflicts with the doc A function's arguments must be hashable to cache it.

This behavior is conceptually incorrect and violates the expectation that “hashable objects are cacheable”, where st.cache_resource is explicitly process-local and does not provide cross-process persistence, and where Python’s own functools.lru_cache accepts any object that is hashable according to standard Python semantics, without imposing serialization requirements.

Reproducible Code Example

import streamlit as st

class Data:
	def __init__(self, payload: bytes):
		self.payload = payload

@st.cache_resource
def transform(data: Data) -> Data:
	return Data(payload=b'new')

data = Data(payload=b'old')
st.write(st.__version__)
st.write(data)
st.write(hash(data))
st.write(transform(data))  # <-- throw error

Steps To Reproduce

No response

Expected Behavior

No response

Current Behavior

Output:

1.50.0

dataData__main__.Data(payload: bytes)
No docs available
payloadbytes | b'old' -- | --

8779468763100

Error message:

# _to_bytes <class '__main__.Data'>: <__main__.Data object at 0x7fc211defdc0>
# _to_bytes <class 'function'>: <function _reconstructor at 0x7fc2af172560>
────────────────────────── Traceback (most recent call last) ───────────────────────────
  ntime/caching/hashing.py:648 in _to_bytes                                             
                                                                                        
  _reduce_ex                                                                            
                                                                                        
     73 │   │   state = None                                                            
     74 │   else:                                                                       
     75 │   │   if base is cls:                                                         
  ❱  76 │   │   │   raise TypeError(f"cannot pickle {cls.__name__!r} object")           
     77 │   │   state = base(self)                                                      
     78 │   args = (cls, base, state)                                                   
     79 │   try:                                                                        
────────────────────────────────────────────────────────────────────────────────────────
TypeError: cannot pickle 'function' object

The above exception was the direct cause of the following exception:

────────────────────────── Traceback (most recent call last) ───────────────────────────
  ntime/caching/hashing.py:650 in _to_bytes                                             
────────────────────────────────────────────────────────────────────────────────────────
UnhashableTypeError

During handling of the above exception, another exception occurred:

────────────────────────── Traceback (most recent call last) ───────────────────────────
  ntime/caching/hashing.py:650 in _to_bytes                                             
────────────────────────────────────────────────────────────────────────────────────────
UnhashableParamError: Cannot hash argument 'data' (of type `__main__.Data`) in 
'transform'.

Is this a regression?

  • Yes, this used to work in a previous version.

Debug info

  • Streamlit version: 1.50.0
  • Python version: Python 3.10.19
  • Operating System:
  • Browser:

Additional Information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions