reflex-dev/reflex · warning · ValueError
Root state must be provided to convert legacy token to BaseS
Error message
Root state must be provided to convert legacy token to BaseStateToken.
What it means
BaseStateToken.from_legacy_token converts an old-style string token into a BaseStateToken and needs the root state class to resolve substate names — without it there is no way to look up state classes, so it raises ValueError. It also emits a deprecation warning because passing plain strings to modify_state is deprecated (removal in 1.0).
Source
Thrown at reflex/istate/manager/token.py:233
The legacy token format is "{ident}_{module_path}.{class_name}".
Args:
legacy_token: The legacy token string to convert.
root_state: The root state instance.
Returns:
A BaseStateToken instance created from the legacy token.
Raises:
ValueError: If the legacy token format is invalid or if the state class cannot be found
"""
from reflex.state import _split_substate_key
if root_state is None:
msg = (
"Root state must be provided to convert legacy token to BaseStateToken."
)
raise ValueError(msg)
console.deprecate(
feature_name="Passing a string to modify_state",
reason="Use rx.BaseStateToken(token, state_cls) instead of the legacy string format",
deprecation_version="0.9.0",
removal_version="1.0",
)
client_token, state_path = _split_substate_key(legacy_token)
state_cls = root_state.get_class_substate(tuple(state_path.split("."))) # type: ignore[union-attr]
return cls(ident=client_token, cls=state_cls)
View on GitHub (pinned to 45b8ed5ab7)
Solutions
- Pass a state class alongside the token: modify_state(token_string, rx.BaseState) or provide root_state to from_legacy_token
- Better: migrate to rx.BaseStateToken(token, StateCls) instead of the legacy string format before 1.0
- If wrapping modify_state generically, thread the state_cls/root_state through your abstraction
Example fix
# before
async with state.modify_state("legacy_token_string") as state:
...
# after
async with state.modify_state(BaseStateToken("legacy_token_string", rx.BaseState)) as state:
... Defensive patterns
Strategy: validation
Validate before calling
if isinstance(token, str) and root_state is None:
raise ValueError("legacy string token requires a state class") # fail fast with a clear message Type guard
def is_legacy_string_token(token: object) -> TypeGuard[str]:
return isinstance(token, str) Prevention
- Migrate stored tokens to BaseStateToken before the 1.0 removal
- Always pass a state class when using string tokens: modify_state(token_str, rx.BaseState)
- Watch for the deprecation warning in CI to catch remaining legacy call sites
When it happens
Trigger: Calling from_legacy_token(token_string, root_state=None), most often indirectly via modify_state("token_string") without a state class so no root can be inferred. Custom middleware that stored string tokens and calls the conversion with only the string hits this directly.
Common situations: Upgrading an app/session layer that persisted legacy string tokens; middleware or auth code that calls modify_state with a raw token string and no state_cls; mixing pre-0.9 token formats with the new BaseStateToken API.
Related errors
- ChildrenTypeError(component=cls.__name__, child=child)
- Do not override _add_style directly. Use add_style instead.
- The component `{comp_name}` only allows the components: {val
- Undefined library for NoSSRComponent
- Component must have a library to bundle.
AI-assisted analysis of reflex-dev/reflex@45b8ed5ab7 (2026-08-28).
Data as JSON: /api/errors/6eeb30079a89520e.
Report an issue: GitHub.