Repository: streamlit/streamlit

Issue:
Cannot print session_state when starting the app
### Summary

(Re-)starting the app or clearing cache leads to a bug when printing the whole `session_state` on the first run.

### Steps to reproduce

Code snippet:

```python
print(st.session_state)
```

**Expected behavior:**

No Bug. No error message.

**Actual behavior:**

![image](https://user-images.githubusercontent.com/32093573/134652095-c575828b-874c-4f71-a36b-16162e824209.png)

### Is this a regression?

This works fine after a re-load. 

### Debug info

- Streamlit version: 0.89.0
- Python version: 3.8.8
- OS version: macOS Big Sur 11.5.2



Discussion:
Hi @Robstaa, thanks for reporting this!

Are you able to produce a full script that acts as a minimal working example (along with steps to be taken to reproduce the issue)? I'm not able to reproduce this myself with the following script on streamlit versions 0.89.0 or 1.0.0 by restarting the server/clearing the cache/triggering a script rerun by toggling the checkbox.

```python
import streamlit as st

st.write(st.session_state)

st.checkbox("checkbox")
```

Resolving patch:
diff --git a/lib/streamlit/state/session_state.py b/lib/streamlit/state/session_state.py
--- a/lib/streamlit/state/session_state.py
+++ b/lib/streamlit/state/session_state.py
@@ -308,13 +308,18 @@ def filtered_state(self) -> Dict[str, Any]:
         wid_key_map = self.reverse_key_wid_map
 
         state: Dict[str, Any] = {}
-        for k, v in self.items():
+
+        # We can't write `for k, v in self.items()` here because doing so will
+        # run into a `KeyError` if widget metadata has been cleared (which
+        # happens when the streamlit server restarted or the cache was cleared),
+        # then we receive a widget's state from a browser.
+        for k in self.keys():
             if not is_widget_id(k) and not is_internal_key(k):
-                state[k] = v
+                state[k] = self[k]
             elif is_keyed_widget_id(k):
                 try:
                     key = wid_key_map[k]
-                    state[key] = v
+                    state[key] = self[k]
                 except KeyError:
                     # Widget id no longer maps to a key, it is a not yet
                     # cleared value in old state for a reset widget


Test patch:
diff --git a/lib/tests/streamlit/state/session_state_test.py b/lib/tests/streamlit/state/session_state_test.py
--- a/lib/tests/streamlit/state/session_state_test.py
+++ b/lib/tests/streamlit/state/session_state_test.py
@@ -497,6 +497,21 @@ def test_filtered_state(self):
             "corge": "grault",
         }
 
+    def test_filtered_state_resilient_to_missing_metadata(self):
+        old_state = {"foo": "bar", "corge": "grault"}
+        new_session_state = {}
+        new_widget_state = WStates(
+            {f"{GENERATED_WIDGET_KEY_PREFIX}-baz": Serialized(None)},
+        )
+        self.session_state = SessionState(
+            old_state, new_session_state, new_widget_state
+        )
+
+        assert self.session_state.filtered_state == {
+            "foo": "bar",
+            "corge": "grault",
+        }
+
     def is_new_state_value(self):
         assert self.session_state.is_new_state_value("foo")
         assert not self.session_state.is_new_state_value("corge")