Why does a session_state variable disappear?

Hi there,
maybe someone else may shed some light on my problem, because i tried, but failed understanding what exactly is happening, and why a specific session_state variable seems to disappear.

I am running this locally with streamlit=1.41.1 and python=3.11.2.

Here is a minimum example:

import streamlit as st
from datetime import datetime

# init session_state
if "trend_how" not in st.session_state:
    st.session_state.trend_how = "start date"

if "trend_start" not in st.session_state:
    st.session_state.trend_start = datetime.today()

if "trend_range" not in st.session_state:
    st.session_state.trend_range = 4


# do something - IRL: save changes into csv
def do_something():
    print("  how: ", st.session_state.trend_how)
    print("start: ", st.session_state.trend_start)
    print("range: ", st.session_state.trend_range)


# radio button to select how to define starting point
st.radio(
    "trend based on",
    ["start date", "date range"],
    key="trend_how",
    on_change=do_something
)

# select _start date_
if st.session_state.trend_how == "start date":
    st.date_input(
        "select 'start date'",
        # format="YYYY-MM-DD",
        key="trend_start",
        on_change=do_something
    )

# select _date range_
if st.session_state.trend_how == "date range":
    st.selectbox(
        "select 'range'",
        [4, 8, 12, 16, 20, 24],
        format_func=lambda x: str(x) + " weeks",
        key="trend_range",
        on_change=do_something
    )

st.divider()
st.write("  how: ", st.session_state.trend_how)
st.write("start: ", st.session_state.trend_start)
st.write("range: ", st.session_state.trend_range)

What is happening and what should happen?

  1. define three session_state variables
  2. define a function which just prints the content of out session_state variables
  3. a radiobutton to decide how a starting date will be calculated
  4. depending on “3.”, show a date_input or a selectbox to specify further parameters
  5. every time the user changes something within the widgets above, a callback_function should be called (IRL changes will be saved into a csv - here: just print the variabels)

What goes wring?
Just click on the radiobuttons twice, alternating between both options! When going back to the upper “start date”, the following error message is shown:

AttributeError: st.session_state has no attribute “trend_start”. Did you forget to initialize it? More info: Add statefulness to apps - Streamlit Docs

Traceback:

File "/Users/adam/Sync/Projects/GravityLog/.venv/lib/python3.11/site-packages/streamlit/runtime/scriptrunner/exec_code.py", line 88, in exec_func_with_error_handling
    result = func()
             ^^^^^^File "/Users/adam/Projects/GravityLog/.venv/lib/python3.11/site-packages/streamlit/runtime/scriptrunner/script_runner.py", line 541, in code_to_exec
    self._session_state.on_script_will_rerun(File "/Users/adam/Projects/GravityLog/.venv/lib/python3.11/site-packages/streamlit/runtime/state/safe_session_state.py", line 66, in on_script_will_rerun
    self._state.on_script_will_rerun(latest_widget_states)File "/Users/adam/Projects/GravityLog/.venv/lib/python3.11/site-packages/streamlit/runtime/state/session_state.py", line 559, in on_script_will_rerun
    self._call_callbacks()File "/Users/adam/Projects/GravityLog/.venv/lib/python3.11/site-packages/streamlit/runtime/state/session_state.py", line 572, in _call_callbacks
    self._new_widget_state.call_callback(wid)File "/Users/adam/Projects/GravityLog/.venv/lib/python3.11/site-packages/streamlit/runtime/state/session_state.py", line 273, in call_callback
    callback(*args, **kwargs)File "/Users/adam/Projects/GravityLog/bug.py", line 18, in do_something
    print("start: ", st.session_state.trend_start)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "/Users/adam/Projects/GravityLog/.venv/lib/python3.11/site-packages/streamlit/runtime/state/session_state_proxy.py", line 131, in __getattr__
    raise AttributeError(_missing_attr_error_message(key))

Solution?
This error message does not appear if I get rid of the if statements and show both, the date_input as well as the selectbox. But I would like to give the user only the option which is defined by the radio button…

Can someone explain what is happening here?

Thanks for reading until here :slight_smile: And for any advice and ideas!

Best,
Adam

Interesting problem. My guess would be that streamlit associates the trend_start variable with the date_input widget. This widget is not rendered when you select the “date range” option. Since the widget is not rendered, streamlit will also remove the associated session variable. You then switch back to the start date option. This will trigger the callback before the rest of the script is executed (and so before the st.session_state.trend_start is reinitialized.