Session state in multipage app - key not initialized

Dear Streamlit community, I dared to write my first multipage app (https://amfupapp.streamlit.app). In fact it is my first streamline app ever, so please apologize if I missed something obvious. I observe an error regarding a session state variable I use. I already studied the documentation, but without success.

I set up the app as described in the streamlit documentation: main file in the top folder and all the other pages in folder „pages“. In the main file „Willkommen.py“ I initialized the session state variable „last_topic“ right at the beginning of the file with a default value ‘X‘:

if 'last_topic' not in st.session_state:
    st.session_state.last_topic = 'X'

In the files of the multi-pages - located in folder „pages“ - the value of “last_topic” is referred. Here the problem arises: sometimes an error is thrown, e.g. in file „04 Technische Kenntnisse Klasse E.py“ (in folder pages) with the following error text (parts extracted below):

KeyError: 'st.session_state has no key "last_topic". Did you forget to 
initialize it? More info: 
https://docs.streamlit.io/develop/concepts/architecture/session-state#initializa
tion'

During handling of the above exception, another exception occurred:

────────────────────── Traceback (most recent call last) ───────────────────────
  /home/adminuser/venv/lib/python3.12/site-packages/streamlit/runtime/scriptru  
  nner/exec_code.py:88 in exec_func_with_error_handling                         
                                                                                
  /home/adminuser/venv/lib/python3.12/site-packages/streamlit/runtime/scriptru  
  nner/script_runner.py:579 in code_to_exec                                     
                                                                                
  /mount/src/amfup/pages/04 Technische Kenntnisse Klasse E.py:667 in <module>   
                                                                                
    664 │   │   st.write('Um die falsch beantworteten Fragen zu exportieren, w  
    665                                                                         
    666 if __name__ == '__main__':                                              
  ❱ 667 │   main()                                                              
    668                                                                         
                                                                                
  /mount/src/amfup/pages/04 Technische Kenntnisse Klasse E.py:43 in main        
                                                                                
     40 │   st.markdown('# Klasse E')                                           
     41 │                                                                       
     42 │   # User switched from other page (e.g. from A)                       
  ❱  43 │   if st.session_state.last_topic != 'E':                              
     44 │   │   st.session_state.reset = False                                  
     45 │   │   st.session_state.last_topic = 'E'                               
     46                                                                         
                                                                                
  /home/adminuser/venv/lib/python3.12/site-packages/streamlit/runtime/state/se  
  ssion_state_proxy.py:131 in __getattr__                                       
────────────────────────────────────────────────────────────────────────────────
AttributeError: st.session_state has no attribute "last_topic". Did you forget 
to initialize it? More info: 
https://docs.streamlit.io/develop/concepts/architecture/session-state#initializa
tion

The error is - unfortunately - not reproducible and appears from time to time on local machine as well as deployed in cloud. From this message I would conclude that “last_topic” was not initialized, but it was (in Willkommen.py) as described above.

I found a hint in Stack Overflow (python - Session state is reset in Streamlit multipage app - Stack Overflow) and included the following line at the very beginning of every page (directly behind: import streamlit as st):

for k, v in st.session_state.to_dict().items():
st.session_state[k] = v

However, in my case, this „hack“ did not solve my problem. I would be very glad for any assistance. Thank you in advance.

What streamlit version do you use?

Sorry, forgot the streamline version: 1.39.

What triggers the error? Is it because you press the refresh button of the browser? What else?

It’s happens (sometimes) when I switch from one (multi)page to another.

Hi, I did some more testing. It seems that the error can be triggered reproducible when after switching from the start page to one of the multi pages (where callback functions are used for handling of check boxes) I press reload in the browser.

1 Like

One way to solve the error due to page reload is to use the switch_page api.

If you have a session variable in the main page and you use it in other pages and when you are in the other page and press the reload button, that would trigger the error because reloading a page creates a new session and so the previous session variable no longer exists.

main.py

if 'a' not in ss:
    ss.a = 1

pages/a.py

if 'a' not in ss:
    st.switch_page(main.py)

If you are in page a, and you press reload, st will switch to the main page, no error message will be shown. But you lost your previous session because of reload.

2 Likes

Hi ferdy, your support is very much appreciated, thank you so much. Switching to main.py helps to avoid the error on reload, that’s perfect.
Is there a way that the user, after switched to main.py is again switched to a.py (or b.py, …)? Then all the session state variables were initialized (in main.py) and the user stays on the page where reload was triggered.

Thank you again for your kind support!

Another way which restores values from previous lost session state due to reload is to use a cookie contoller. In this case there is no need to use the switch page api.

The idea is to store all important session variables in a cookie so that we can restore them in the event of page reloads.

Here is a sample code.

import streamlit as st
from streamlit import session_state as ss
from streamlit_cookies_controller import CookieController

controller = CookieController()

Define session variable in main page and store it in a cookie.

if 'cnt' not in ss:
    ss.cnt = 0

def main():
    # Backup
    controller.set('cnt', ss.cnt)
    st.markdown(f'**cnt: {ss.cnt}**')


if __name__ == "__main__":
    main()

Now in other page, try to detect for page reload.

import time

import streamlit as st
from streamlit import session_state as ss
from streamlit_cookies_controller import CookieController


COOKIE_WAIT_TIME_SEC = 1
controller = CookieController()


# If user reloads this page.
if 'cnt' not in ss:
    with st.spinner('please wait restoring data ...'):
        cookies = controller.getAll()
        time.sleep(COOKIE_WAIT_TIME_SEC)

    # Restore session variable value from cookie
    ss.cnt = cookies['cnt']

Full sample code.

app.py as main page.


import streamlit as st
from streamlit import session_state as ss
from streamlit_cookies_controller import CookieController


controller = CookieController()


if 'cnt' not in ss:
    ss.cnt = 0


def main():
    # Backup
    controller.set('cnt', ss.cnt)

    st.markdown(f'**cnt: {ss.cnt}**')


if __name__ == "__main__":
    main()

pages/shop.py

import time

import streamlit as st
from streamlit import session_state as ss
from streamlit_cookies_controller import CookieController


COOKIE_WAIT_TIME_SEC = 1
controller = CookieController()


# If user reloads this page.
if 'cnt' not in ss:
    with st.spinner('please wait restoring data ...'):
        cookies = controller.getAll()
        time.sleep(COOKIE_WAIT_TIME_SEC)

    # Restore session variable value from cookie
    ss.cnt = cookies['cnt']


def cnt_cb():
    ss.cnt = ss.cntk

st.number_input('QTY', value=ss.cnt, step=1, min_value=0,
                max_value=100, on_change=cnt_cb, key='cntk')

requirements.txt

streamlit==1.39
streamlit-cookies-controller==0.0.4

From local test, this worked for me. You can reload on shop page and it will restore the old value.

Also worked when deployed in digitalocean.

  1. Open app in laptop, set counter to 4
  2. Open app in mobile phone, set counter to 1, reload shop page, counter is restored to 1 and not 4.
1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.