Skip to content

A str-annotated field whose default_factory produces browser storage is never treated as browser storage #7498

Description

@masenf

Severity: LOW, pre-existing on main (0.10 dev). Found while addressing review on #7495.

What happens

A field whose default_factory produces a browser storage value, with a plain annotation, is never treated as browser storage:

class State(rx.State):
    theme: str = rx.field(default_factory=lambda: rx.LocalStorage("light", name="theme"))

State._is_client_storage("theme") is False, the var is not compiled into the client storage section, and it is never synced with the browser. Each instance just holds a LocalStorage instance as an ordinary str value. Nothing warns.

The same declaration with the storage annotation (theme: rx.LocalStorage = rx.field(default_factory=...)) is detected through the annotation (but see the separate hydration error issue filed with this one).

Why

BaseState._is_client_storage (reflex/state.py) only looks at field.default and at the annotation. A factory only reveals what it produces when called, and nothing calls it at class creation. After #7495 a plain assignment through the class (State.theme = "dark") calls the factory once and turns the field into browser storage, so the var is detected from then on; without such an assignment it is not. Note also that _is_client_storage is cached per class, so a class assignment made after the first lookup would not be seen until the cache is cleared.

Options

  • Evaluate a declared default_factory once at class creation when the annotation is not a storage type, and classify the field by the result (cost: one factory call per such field per class).
  • Or reject / warn about a factory-produced storage default and document that browser storage must be declared as a default value or with a storage annotation.

Generated by Claude Code

Activity

  1. added theissue type on Oct 7, 2026
  2. linear-code commented on Oct 7, 2026

    @linear-code
  3. added a commit that references this issue on Oct 7, 2026
  4. self-assigned this
    on Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions