Invalid JavaScript Code Generation with EventHandler args_spec Using rx.Var Expressions
Describe the bug
Reflex generates invalid JavaScript code when using a custom args_spec in an EventHandler that returns rx.Var(f"{event}?.formData"). The generated code places an expression (_event?.formData) in an argument list, causing a JavaScript syntax error during compilation.
To Reproduce Steps to reproduce the behavior:
- Create a custom event signature function:
from reflex.vars import ObjectVar
from reflex.event import JavascriptInputEvent
from typing import Dict, Any
def submit_signature(
event: ObjectVar[JavascriptInputEvent],
) -> tuple[Var[Dict[str, Any]], Var[str]]:
return (
rx.Var(f"{event}?.formData"),
rx.Var(f"{event}?.retrievedSchema.title"),
)
- Create a component with the EventHandler:
class RjsfReflex(rx.Component):
# ... other component properties
on_submit: rx.EventHandler[submit_signature]
# ...
- Use the component with ClientStateVar:
var_name = ClientStateVar.create("var_name_js", "dummy_data")
# This triggers the bug
Form(
on_submit=lambda data: rx.call_function(ClientStateVar.set_value(data))
)
- Run
reflex runand observe the JavaScript compilation error
- Code/Link to Repo: https://github.com/LeoGrosjean/rjsf-reflex
Expected behavior
The component should generate valid JavaScript code that properly handles form data extraction and submission without syntax errors. The args_spec should allow accessing nested properties like formData from the event object.
Screenshots Error output:
[plugin:vite:oxc] Expected `,` but found `=>`
/Users/leoh/PycharmProjects/rjsf-reflex/rjsf_reflex_demo/.web/app/routes/_index.jsx:76:175
`,` expected
74 |
75 | return (
76 | jsx(Form,{className:"schema-form",css:({ ["maxWidth"] : "100%" }),id:"no",onSubmit:((_event) => (addEvents([(Event("_call_function", ({ ["function"] : ((_event?.formData) => (refs['_client_state_setResult'](_event?.formData))), ["callback"] : null }), ({ })))], [_event], ({ })))),ref:ref_no,schema:reflex___state____state__rjsf_reflex_demo___rjsf_reflex_demo____state.schema_rx_state_,validator:validator},)
| ^^
77 |
Specifics (please complete the following information):
- Python Version: 3.12.8
- Reflex Version: 0.8.8
- OS: macOS sequoia
Additional context
- This occurs when trying to create a React JSON Schema Form (RJSF) wrapper component
- The problem appears to be that Reflex treats
rx.Var(f"{event}?.formData")as an expression but places it in a context where a parameter name is expected
does it work with run_script instead of call_function?
same error !
the issue is here: https://github.com/reflex-dev/reflex/blob/main/reflex/experimental/client_state.py#L233
args_names=(re.sub(r"(\[\".*\"\]|\?.*)", "", value_str),)
should fix it
will run pre-commit and make a PR !
@adhami3310 , Is this issue still open? I can take it up and resolve it
the issue is open, even better if the solution wouldn't just knock the can down the road by changing the regex, but /shrug
@adhami3310 ,
Hey, I dug into the issue more deeply and here’s a clearer breakdown of what’s actually happening under the hood, along with the real root cause and the direction for an actual fix.
Summary of the Bug
When an EventHandler uses a custom args_spec that returns multiple Var expressions (e.g. Var(f"{event}?.formData") and similar), Reflex fails during compilation.
Symptoms
- Validation incorrectly reports:
Event on_submit only provides 1 argument
even though args_spec correctly contains two Var entries.
- The JS renderer attempts to treat
Varobjects like iterable components, which triggers:
VarTypeError: 'in' operator not supported for Var types
- Compilation then aborts before JS generation, or produces malformed JS like:
((_event?.formData) => ...)
which is placed where an argument value should be.
Root Cause (Not Regex Related)
This isn’t a regex issue - it’s a deeper structural problem:
1. _RenderUtils.render() and template logic treat Var as a component
The renderer performs checks like:
if "iterable" in component:
This calls __contains__ on a Var, which raises VarTypeError.
But Var should be treated as an atomic JS expression, e.g.:
_event?.formData
—not introspected or iterated.
2. Event validation counts args after templating, not from args_spec
Since _RenderUtils.render() crashes on Var before producing a usable structure,
the validation layer only sees one argument, and throws:
EventFnArgMismatchError
Even though args_spec clearly returns two arguments.
3. JS codegen inherits a corrupted structure
Instead of generating:
handler((_event?.formData), (_event?.retrievedSchema.title))
it produces malformed code such as:
((_event?.formData) => ...)
because the argument expression is being wrapped as a function.
Correct Fix (No Regex)
A proper fix needs two foundational changes:
A. Fix Var handling in _RenderUtils.render()
Add an early return:
if isinstance(component, Var):
return str(component) # render raw JS expression
This guarantees that:
- Vars aren’t treated like components
- Template logic will never call
inor iterate them
B. Fix event argument validation
Argument counting should happen directly from the parsed args_spec,
not from the rendered/templated output (which is unstable when Vars are involved).
This ensures:
- Two Vars → two arguments
- No accidental collapsing of args
- No false
EventFnArgMismatchError
I will submit a PR with a minimal patch demonstrating the fix.
more smaller repro
import reflex as rx
last_x = rx._x.client_state("last_x", 0)
def _get_client_x_spec(event: rx.vars.ObjectVar[rx.event.JavascriptMouseEvent]) -> tuple[rx.Var]:
return rx.Var(f"{event}?.clientX"),
# If we return it like _this_, then it almost works.
return (event.clientX, )
class XButton(rx.components.radix.button.__self__):
on_click: rx.EventHandler[_get_client_x_spec]
def index() -> rx.Component:
return rx.container(
rx.vstack(
rx.badge(last_x.value.to_string()),
XButton.create(
on_click=lambda x: rx.call_function(last_x.set_value(x)),
),
),
)
app = rx.App()
app.add_page(index)
more smaller repro
import reflex as rx
last_x = rx._x.client_state("last_x", 0)
def _get_client_x_spec(event: rx.vars.ObjectVar[rx.event.JavascriptMouseEvent]) -> tuple[rx.Var]: return rx.Var(f"{event}?.clientX"),
# If we return it like _this_, then it almost works. return (event.clientX, )class XButton(rx.components.radix.button.self): on_click: rx.EventHandler[_get_client_x_spec]
def index() -> rx.Component: return rx.container( rx.vstack( rx.badge(last_x.value.to_string()), XButton.create( on_click=lambda x: rx.call_function(last_x.set_value(x)), ), ), )
app = rx.App() app.add_page(index)
Thanks for the repro, @masenf - this makes the issue clearer.
Just to confirm: EventHandler.args_spec only supports typed event Vars (like event.clientX), and the failure happens because string-backed Vars (Var(f"{event}?.clientX")) aren’t valid in that pipeline.
Before I dig in: should the fix be enforcing typed Vars only, or extending args_spec to support string expressions?
Happy to work on the proper solution - just want to target the right subsystem.