You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 02b92bb
Browse filesBrowse the repository at this point in the historyBrowse files
Detect a frontend/backend state schema mismatch at connect and prompt a reload (#7553)
The compiled frontend and the backend can come from different builds: a
redeploy with a page kept open, mixed backend versions behind a load
balancer, or an api_url pointing at another backend. The #7435 fallback
skips deltas for unknown substates, but the skew stays hidden from users
and a changed var in a known state is never detected.
BaseState._to_frontend_schema() hashes what the compiled frontend depends
on over the whole tree: each state's full name, its frontend var names and
types (base and computed), and its event handler names. Defaults and values
are left out. It is lru-cached like _to_schema() and cleared with it, so a
state registered later invalidates the cached root. The compiler writes the
hash into the context module as stateSchema; the frontend sends it in the
socket.io CONNECT auth under state_schema on the first connect and every
reconnect; EventNamespace.on_connect compares it with the backend's hash,
emits one state_mismatch event to that client, logs one warning, and still
hydrates. A missing hash (old frontend) is ignored, and an old backend
ignores the new auth key.
On a mismatch in prod the page reloads once, guarded by the existing
reflex_last_reloaded_on_error cooldown, so mixed versions cannot loop; a
mismatch inside the cooldown shows a banner with a reload button. In dev
only a console warning is logged, since a backend hot reload can reconnect
before Vite serves the rebuilt bundle.
Closes#7552.
Claude-Session: https://claude.ai/code/session_01EYJS7NPEz1gNkXZdqQDTA3
Copy file name to clipboardExpand all lines: docs/utility_methods/exception_handlers.md
+16-2Lines changed: 16 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -15,9 +15,23 @@ The `frontend` errors are coming from the JavaScript side of the application, wh
15
15
16
16
### Frontend and backend state mismatches
17
17
18
-
If a backend update names a substate that the compiled frontend does not recognize, Reflex skips that substate. Updates to known substates and subsequent events continue to work. Reflex warns in the browser console and reports each unknown substate to `frontend_exception_handler` once per connection.
18
+
The compiled frontend and the backend can come from different builds of the app: a backend deploy changes the state while a browser keeps the old page, two backend versions run behind one load balancer during a rolling deploy, or `api_url` points at a backend that did not serve the frontend. The frontend then holds states, vars and event handlers the backend does not know, or the other way around.
19
19
20
-
This can happen when a backend deploy adds state while a browser still uses an older frontend bundle. Refresh the page to load the matching bundle. If the warning persists, rebuild the frontend and check that `api_url` points to the intended backend. Reflex only skips unknown substates; it does not reconcile other differences, such as a renamed state or a changed var.
20
+
Reflex detects this when the frontend connects. The compiled frontend carries a hash of the state tree it was built for (the state names, their frontend vars with types, and their event handler names) and sends it with every socket connect and reconnect. The backend computes the same hash over its own state tree and compares the two. Defaults and values are not part of the hash, so changing a default value does not count as a mismatch.
21
+
22
+
On a mismatch:
23
+
24
+
- In production, the page reloads once to fetch the new frontend. The reload shares the `REFLEX_AUTO_RELOAD_COOLDOWN` (default 10 seconds) with the automatic reload on frontend errors, so a page never reloads in a loop. When a reload already happened inside the cooldown (the reload landed on the same mismatch, for example a cached page or mixed backend versions) the page shows a banner saying a new version of the app is available, with a reload button, and keeps working as well as it can.
25
+
- In development, the frontend only logs a warning in the browser console. A backend hot reload can reconnect before the frontend dev server serves the rebuilt page, which gives a short-lived mismatch that resolves on its own.
26
+
27
+
The backend logs one warning per mismatched connection.
28
+
29
+
Independently of that check, if a backend update names a substate that the compiled frontend does not recognize, Reflex skips that substate. Updates to known substates and subsequent events continue to work. Reflex warns in the browser console and reports each unknown substate to `frontend_exception_handler` once per connection. If the warning persists after a reload, rebuild the frontend and check that `api_url` points to the intended backend. Reflex only skips unknown substates; it does not reconcile other differences, such as a renamed state or a changed var.
30
+
31
+
```md alert warning
32
+
# Load balancers need sticky sessions.
33
+
When several backend versions run behind one load balancer, each reconnect can land on a different version, and the frontend cannot match all of them. Pin each client to one backend (sticky sessions) or to one deployment during a rollout; the framework cannot work around this.
Detect a frontend built for another version of the app when it connects to the backend. The compiled frontend now carries a hash of the state tree (state names, frontend vars and event handler names) and sends it on every socket connect. On a mismatch, a production page reloads once (sharing the `REFLEX_AUTO_RELOAD_COOLDOWN` with the reload on frontend errors) and otherwise shows a "new version available" banner with a reload button; in dev mode it only logs a console warning. Load balancers serving several backend versions still need sticky sessions.
The compiled context module exports `stateSchema`, a hash of the state tree the frontend was built for, and the frontend sends it in the socket.io CONNECT `auth` payload under the `state_schema` key. The backend answers a mismatch with the new `state_mismatch` socket event; in production, the frontend then reloads once per cooldown window or shows a "new version available" banner, while in development it only warns in the console.
0 commit comments