App state disappears after ~16min - seeing recursion error in number_input.py

I’m just learning streamlit so i created a toy app that implements a simple timer. The code (see below) uses ‘rerun’ to update the progress of the countdown

I noticed that with long timers after ~16 min the app stops and only the title ‘Timer Demo’ is displayed

I assume this is something I am doing wrong due to my lack of understanding of the framework

Here is the stack trace


Here is the code:

import streamlit as st
import time
import os

DEFAULT_TIMER=1500

# Initialize session state variables
if 'timer_seconds' not in st.session_state:
    st.session_state.timer_seconds = DEFAULT_TIMER

if 'time_remaining' not in st.session_state:
    st.session_state.time_remaining = DEFAULT_TIMER

if 'timer_state' not in st.session_state:
    st.session_state.timer_state = 'idle'


# Timer control functions
def start_timer():
    if st.session_state.timer_state == "idle":
        st.session_state.time_remaining = st.session_state.timer_seconds
    st.session_state.timer_state = "running"


def pause_timer():
    st.session_state.timer_state = "paused"


def reset_timer():
    st.session_state.timer_state = "idle"
    st.session_state.time_remaining = st.session_state.timer_seconds


def progress_update():
    # Progress bar
    st.progress(st.session_state.time_remaining / st.session_state.timer_seconds)
    st.text(f'{st.session_state.time_remaining}s remaining')
    time.sleep(1)


def sound_alert():
    try:
        # works on macOS
        os.system( "say 'times up!'" )
    except:
        pass


# App layout
st.title("Timer Demo")

# User sets the timer
st.session_state.timer_seconds = st.number_input("Set timer (in seconds):", min_value=0,
                                                 value=st.session_state.timer_seconds, key="set_timer")

# Timer buttons
col1, col2, col3 = st.columns(3)
with col1:
    st.button("Start", on_click=start_timer)
with col2:
    st.button("Pause", on_click=pause_timer)
with col3:
    st.button("Reset", on_click=reset_timer)

# Timer logic
if st.session_state.timer_state == "running":
    if st.session_state.time_remaining > 0:
        progress_update()
        st.session_state.time_remaining -= 1
        st.rerun()
    else:
        st.session_state.timer_running = False
        st.balloons()
        sound_alert()
        reset_timer()
elif st.session_state.timer_state == "paused":
    progress_update()
    st.rerun()

Full stack trace:

Exception in thread ScriptRunner.scriptThread:
Traceback (most recent call last):
  File "/Users/rupert/scratch/togalit/venv/lib/python3.10/site-packages/streamlit/runtime/scriptrunner/script_runner.py", line 535, in _run_script
    exec(code, module.__dict__)
  File "/Users/rupert/scratch/togalit/src/togalit/timer.py", line 53, in <module>
    st.session_state.timer_seconds = st.number_input("Set timer (in seconds):", min_value=0,
  File "/Users/rupert/scratch/togalit/venv/lib/python3.10/site-packages/streamlit/runtime/metrics_util.py", line 397, in wrapped_func
    result = non_optional_func(*args, **kwargs)
  File "/Users/rupert/scratch/togalit/venv/lib/python3.10/site-packages/streamlit/elements/widgets/number_input.py", line 237, in number_input
    return self._number_input(
  File "/Users/rupert/scratch/togalit/venv/lib/python3.10/site-packages/streamlit/elements/widgets/number_input.py", line 300, in _number_input
    int_args = all(
  File "/Users/rupert/scratch/togalit/venv/lib/python3.10/site-packages/streamlit/elements/widgets/number_input.py", line 301, in <genexpr>
    isinstance(a, (numbers.Integral, type(None), str))
  File "/usr/local/Cellar/python@3.10/3.10.13_2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/abc.py", line 119, in __instancecheck__
    return _abc_instancecheck(cls, instance)
  File "/usr/local/Cellar/python@3.10/3.10.13_2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/abc.py", line 123, in __subclasscheck__
    return _abc_subclasscheck(cls, subclass)
RecursionError: maximum recursion depth exceeded in comparison

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  <snipped>
"/usr/local/Cellar/python@3.10/3.10.13_2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/traceback.py", line 353, in extract
    limit = getattr(sys, 'tracebacklimit', None)
RecursionError: maximum recursion depth exceeded while calling a Python object

Looks like I ran into this issue: maximum recursion depth exceeded · Issue #3094 · streamlit/streamlit · GitHub

I fixed the script by removing rerun() & used the autorefresh component from the thread: GitHub - kmcgrady/streamlit-autorefresh: An autorefresh component for Streamlit apps