Secrets management unhashable in @st.cache

I am using the st.secrets() feature to supply my Streamlit app with a login token for an on-demand Dask Cluster via Coiled.io

The script runs fine before including the st.secrets() line but fails when I include it with the following message in the app terminal, copied below.

I’m not familiar enough with hashing to understand what this actually means :see_no_evil: – any help here would be very much appreciated!

streamlit.hashing.UnhashableTypeError: Cannot hash object of type `_thread.RLock`, found in the body of `get_client()`.

While caching the body of `get_client()`, Streamlit encountered an
object of type `_thread.RLock`, which it does not know how to hash.
To address this, please try helping Streamlit understand how to hash that type
by passing the `hash_funcs` argument into `@st.cache`. For example:

@st.cache(hash_funcs={_thread.RLock: my_hash_func})
def my_func(...):
    ...

If you don't know where the object of type `_thread.RLock` is coming
from, try looking at the hash chain below for an object that you do recognize,
then pass that to `hash_funcs` instead:

Object of type _thread.RLock: <unlocked _thread.RLock object owner=0 count=0 at 0x7f2b088cedb0>

Object of type builtins.tuple: ('_lock', <unlocked _thread.RLock object owner=0 count=0 at 0x7f2b088cedb0>)

Object of type builtins.dict: {'_secrets': {'coiled_token': '<hidden>', 'coiled_account': '<hidden>'}, '_lock': <unlocked _thread.RLock object owner=0 count=0 at 0x7f2b088cedb0>, '_file_watcher_installed': True, '_file_path': '/app/streamlit/.streamlit/secrets.toml'}

Object of type streamlit.secrets.Secrets: {'coiled_token': '<hidden>', 'coiled_account': '<hidden>'}

Object of type builtins.function: <function get_client at 0x7f2b5b4e6ca0>
1 Like

Hi @rrpelgrim :wave:

Are you including st.secrets[] in your get_client() function and decorating the function with @st.cache()? If so, you can turn off hashing for the object of type _thread.RLock by modifying the decorator to look like the following:

@st.cache(hash_funcs={"_thread.RLock": lambda _: None})
def get_client():

Happy Streamlit’ing! :balloon:
Snehan

1 Like

Hi @snehankekre, thanks for your response.
See my updated code below. This is still not working unfortunately.
Any pointers as to what I should be doing differently are very welcome!

@st.cache(allow_output_mutation=True, hash_funcs={"_thread.RLock": lambda _: None})
def get_client():
    cluster_state.write("Starting or connecting to Coiled cluster...")
    cluster = coiled.Cluster(
        n_workers=10,
        name="coiled-streamlit",
        software="coiled-examples/streamlit",
        account=st.secrets("coiled_account"),
    )

    client = Client(cluster)
    return client

This fails with

CacheKeyNotFoundError("Key not found in mem cache")
streamlit.caching.CacheKeyNotFoundError: Key not found in mem cache
During handling of the above exception, another exception occurred:

Traceback (most recent call last):

  File "/home/appuser/venv/lib/python3.8/site-packages/streamlit/script_runner.py", line 350, in _run_script
    exec(code, module.__dict__)
  File "/app/streamlit/coiled-streamlit-with-sharing.py", line 43, in <module>
    client = get_client()
  File "/home/appuser/venv/lib/python3.8/site-packages/streamlit/caching.py", line 543, in wrapped_func
    return get_or_create_cached_value()
  File "/home/appuser/venv/lib/python3.8/site-packages/streamlit/caching.py", line 527, in get_or_create_cached_value
    return_value = func(*args, **kwargs)
  File "/app/streamlit/coiled-streamlit-with-sharing.py", line 37, in get_client
    account=st.secrets("coiled_account"),

TypeError: 'Secrets' object is not callable

Use square brackets instead of parenthesis :grinning_face_with_smiling_eyes:

st.secrets["coiled_account"]

Best, :balloon:
Snehan

hits himself on the head
Of course! Sorry to bother you with that one… :roll_eyes:

Hi!
I’m having a similar problem where I’m trying to pass a boto3 session to a function that then runs a SQL query.
I get an error UnhashableTypeError: Cannot hash object of type _thread.lock, found in the arguments of load_trip_data().

How would I deal with this?

This is my code

@st.cache()
def load_trip_data(role_session: Session):

    run_query_with_this_session

Hi @AditSanghvi94,

What does the load_trip_data() function return? If the function returns the results of a SQL query, you can decorate the function with @st.experimental_memo. If it returns a non-data object, such a boto3 session, decorate the function with @st.experimental_singleton.

Read more about our new and improved cache primitives and when to use memo vs singleton here: Experimental cache primitives - Streamlit Docs

The following is not guaranteed to work, but if you want to continue using the slower @st.cache, replace it with the following:

@st.cache(allow_output_mutation=True, hash_funcs={"_thread.RLock": lambda _: None})

Best, :balloon:
Snehan

The function runs a SQL query on athena, loads some data into a pandas dataframe and returns the dataframe

Thanks for the clarification. What you’re looking for is @st.experimental_memo. If you receive a hashing related error after using memo, you can prefix the unhashable function argument with an underscore, like so:

@st.experimental_memo
def load_trip_data(_role_session: Session):

    run_query_with_this_session

Any parameter whose name begins with _ will not be hashed. You can use this as an “escape hatch” for parameters that are not hashable.

Best, :balloon:
Snehan