Why do default values cause a session state warning?

Yes, I understand that. However, the text_input does not behave in the way I need it to. I will create a new post to explain since it is a specific use-case. Thanks for the help. This community is quick to respond and that is awesome!

Thanks for the suggestion :slight_smile: Here is the full issue I’m having. I figured it’s best to create a new post since there are a few issues that using a key and value almost solved. Text_input behavior for updating a session state value is not intuitive for my use-case

For me, the issue is that avoiding setting default and keys doesn’t seem possible. I have a loop containing

w_param = st.number_input(
    label = f"Width {n}",
    label_visibility = "collapsed",
    value = float(0.1),
    key = f"w_input_{n}")
    ....

and then later in a process + update widgets step,

for n, chunk in enumerate(list(chunks(popt, 9))):
    ss[f"w_input_{n+1}"] = str(round(chunk[0],2))
    ...

Maybe that looks crazy, but it does what we need, and I’ve been struggling to get rid of the widget set warning (which only appears on first load) for over half a year!

Any other ideas?

I don’t understand how you can get just a warning. After providing the missing parts, I ran your code and got an error, as expected:

StreamlitAPIException: st.session_state.w_input_1 cannot be modified after the widget with key w_input_1 is instantiated.

Creating a running example of what my app does is not feasible, I am afraid. Abstracting it from the running code would be very complicated. I know - this means I’ve probably written bad code if I can’t isolate parts! :grimacing:

But, it does work. The widget(s) st.session_state.w_input_{n} are initialised, with a value. Later, a process runs (a curve-optimisation) correcting and refining this value, which it redefines as st.session_state.w_input_{n} , and the input widget reflects this, changing from being the input to the current output.

Works fine, except for the first run The widget with key "w_input_1" was created with a default value but also had its value set via the Session State API.

Not sure if it help with diagnosis, but it never complains about w_input_2, 3 etc, and it resolves after first run, until streamlit is closed (closing the tab is fine). Also, it isn’t just the parameter w, but another 8 parameters (times number of curves being fitted, so at times 30 or more parameters) which get processed and updated, and it works fine. But it only even complains about w_input_1 :person_shrugging:

  1. Never assign a value to key’s widget logically after the widget function is called in the script. If you cannot move the logic to before the widget then save the “new” widget values into some other key, and call st.experimental_rerun with the very first thing in your script to check for these temporary keys, copy the data to the widget keys, then delete the temporary keys. However, I expect moving your optimization process to a callback would be better.

  2. If you want to manually control the value of a widget by its key, just avoid using the default value parameter altogether. Set its default by initializing a value assigned to its key in session state before the widget.

Here’s a toy example that hopefully illustrates that:

import streamlit as st

def widget(n):
    # Set initial value through session state, not the value argument
    if f'w_input_{n}' not in st.session_state:
        st.session_state[f'w_input_{n}'] = .1
    return st.number_input(f'Dimension {n}', key=f'w_input_{n}')

def optimize():
    # Some function modifying the values
    for i in range(st.session_state['dimensions']):
        st.session_state[f'w_input_{i}'] += 1
    st.session_state['dimensions'] += 1

if 'dimensions' not in st.session_state:
    st.session_state['dimensions'] = 1

for i in range(st.session_state['dimensions']):
    widget(i)

st.button('Optimize', on_click=optimize)
1 Like

Thanks for this example @mathcatsand - I can see how that works, but for me it doesn’t work. I already have a very long function where many session state items are initialised, and adding this widget to it doesn’t resolve things.

An issue with solving this is that the warning doesn’t say what line is causing the warning, so I cannot look into it. Currently, there is a pretty dense network of “set widget”, “run process”, “update slider” operations, and working out which one causes the warning has defeated me. It is also difficult to debug, as we need to completely stop streamlit and rerun the analysis each time - because the warning only appears on first run, and only for widget 1 (and I can’t figure out why it doesn’t warn about the other dozen parameters). If I could find that line, I would add “if it gives you a warning, rerun the whole thing” catch.

While solving the code by obeying the rules is the best idea, given that it works (I have never seen ignoring this warning resulting in a broken app), can’t it be ignored?

Yes, you can ignore the warning. The value set by key takes precedence over the specified default value. The warning does nothing more than that; warn you that you’ve given Streamlit conflicting information.

It only warns when the widget is initialized. Once the widget exists, Streamlit is not concerned if it has a different value than the default because that is to be expected from use.

This is definitely not a beautiful solution by any means and not a good thing to do for later debugging, but if you want to simply get rid of the warning in any case, you can hack this into the top of your script:

st.elements.utils._shown_default_value_warning=True

Not sure if the API changed, but this is how I did it in the past until I discovered how to properly solve this problem :sweat_smile: (I understand, your case is possibly different).

Thanks @Wally , agreed not ideal, but right now I need to showcase our app to colleagues and just want the warnings to go away! And this works for me! :partying_face:

Might ressurect this undead thread in due course :skull: :grimacing: :smiling_face:

Yes, i know it’s ugly. :laughing: You should definitely turn this off while developing/debugging.

it looks like as of version 1.23 there is a switch implemented for exactly this issue:

  • :shushing_face: The new global.disableWidgetStateDuplicationWarning configuration option allows the silencing of warnings triggered by setting widget default values and keyed session state values concurrently (#3605, #6640). Thanks, @antonAce!

Check the announcement: Version 1.23.0

1 Like

That’s nice! Just to be sure, one way to implement this would be to add

[global]
disableWidgetStateDuplicationWarning = true

to the configuration file?

Update: Yes, according to the corresponding PR it looks like this (and I had an error in my first version, writing [general] instead of [global])