reflex icon indicating copy to clipboard operation
reflex copied to clipboard

Invalid JavaScript Code Generation with EventHandler args_spec Using rx.Var Expressions

Open LeoGrosjean opened this issue 4 months ago • 6 comments

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:

  1. 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"),
    )
  1. Create a component with the EventHandler:
class RjsfReflex(rx.Component):
    # ... other component properties
    on_submit: rx.EventHandler[submit_signature]
    # ...
  1. 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))
)
  1. Run reflex run and 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

LeoGrosjean avatar Aug 26 '25 21:08 LeoGrosjean

does it work with run_script instead of call_function?

adhami3310 avatar Aug 26 '25 22:08 adhami3310

same error !

Image

LeoGrosjean avatar Aug 26 '25 22:08 LeoGrosjean

the issue is here: https://github.com/reflex-dev/reflex/blob/main/reflex/experimental/client_state.py#L233

adhami3310 avatar Aug 26 '25 23:08 adhami3310

args_names=(re.sub(r"(\[\".*\"\]|\?.*)", "", value_str),)

should fix it

will run pre-commit and make a PR !

LeoGrosjean avatar Sep 06 '25 13:09 LeoGrosjean

@adhami3310 , Is this issue still open? I can take it up and resolve it

ParagGhatage avatar Nov 13 '25 06:11 ParagGhatage

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 avatar Nov 13 '25 07:11 adhami3310

@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 Var objects 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 in or 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.

ParagGhatage avatar Nov 14 '25 18:11 ParagGhatage

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)

masenf avatar Nov 14 '25 20:11 masenf

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.

ParagGhatage avatar Nov 14 '25 21:11 ParagGhatage