Skip to content

Let the app choose what happens on a state schema mismatch, instead of an immediate reload #7563

Open

Description

@H4dr1en

Context

#7553 (closing #7552) detects a frontend built for another state tree than the backend's, which is very welcome: a page left open across a deploy used to drop events silently. In production it then reloads the page at once, or shows a banner when a reload already happened within REFLEX_AUTO_RELOAD_COOLDOWN.

Problem

In a Kubernetes rolling update, each replaced pod closes its sockets, and every open tab reconnects to a new pod within seconds. After #7553, a deploy that adds a var or renames an event handler reloads every open tab at that moment, whatever the user is doing:

  • a drag or a drawing in progress is lost;
  • input typed but not yet sent is lost;
  • in apps used in long sessions, the reload lands mid-task, with no warning.

The app knows better than the framework when a reload is harmless: after an autosave, when the user pauses, or after asking. Today it cannot take that decision:

  • there is no setting or hook for this path;
  • the only lever is REFLEX_AUTO_RELOAD_COOLDOWN. Setting it above the current epoch time in milliseconds (about 56 years) makes the first mismatch show the banner instead of reloading, but it also disables the automatic reload on frontend errors, which shares the cooldown. That is a hack, not a setting.

We understand that load balancer skew is out of scope, as #7552 says. This request is only about what the page does once a mismatch is detected.

Proposal

Either of these would be enough; the first is the smallest:

  1. A setting for the production action, for example rx.Config(state_mismatch_action="reload" | "banner" | "none"), defaulting to today's "reload". "banner" shows the existing banner with its Reload button; "none" only logs, for apps that handle it themselves.
  2. A cancelable browser event before the default action, for example window.dispatchEvent(new CustomEvent("reflex:state-mismatch", { cancelable: true, detail: { frontend, backend } })) in handleStateMismatch. When a listener calls preventDefault(), Reflex skips its reload and banner. Apps can then show their own notice and reload at a safe moment.

With either, the #7435 fallback (unknown substates skipped) keeps the page as usable as it is today until the app reloads.

Prior art

The prior art #7552 lists leaves the decision to the app: SvelteKit's updated store and Phoenix LiveView's phx-track-static only report that a new version exists; the app decides when to reload.

Activity

  1. linear-code commented on Oct 14, 2026

    @linear-code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions