Skip to content

Preserve bound args for upload handlers#6602

Merged
masenf merged 10 commits into
reflex-dev:mainfrom
puneetdixit200:fix/upload-bound-event-args
Jun 12, 2026
Merged

Preserve bound args for upload handlers#6602
masenf merged 10 commits into
reflex-dev:mainfrom
puneetdixit200:fix/upload-bound-event-args

Conversation

@puneetdixit200

Copy link
Copy Markdown
Contributor

All Submissions:

  • Have you followed the guidelines stated in CONTRIBUTING.md file?
  • Have you checked to ensure there aren't any other open Pull Requests for the desired changed?

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Changes To Core Features:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
  • Have you successfully ran tests with your changes locally?

Description

Fixes #5290.

EventHandler.__call__ returned immediately when it saw rx.upload_files(...) or rx.upload_files_chunk(...), so any other bound arguments supplied to the same event handler were dropped. This keeps the upload client-handler spec, but appends normal bound handler arguments to the resulting EventSpec so on_drop=State.handle_upload(rx.upload_files(...), field) preserves field.

AI-assisted: OpenAI Codex, with local review and verification.

Testing

  • Red before fix: uv run pytest tests/units/components/core/test_upload.py::test_upload_files_preserves_bound_event_args -q failed because field was missing from the upload event args.
  • uv run pytest tests/units/components/core/test_upload.py -q
  • uv run pytest tests/units/test_event.py -q
  • uv run pytest tests/units/test_app.py -q -k 'upload and not compile_writes_upload_files_provider_app_wrap'
  • uv run ruff check packages/reflex-base/src/reflex_base/event/__init__.py tests/units/components/core/test_upload.py
  • uv run pyright packages/reflex-base/src/reflex_base/event/__init__.py tests/units/components/core/test_upload.py (0 errors, 1 existing warning in event/__init__.py)
  • git diff --check

Note: uv run pytest tests/units/test_app.py -q -k upload currently fails in unrelated test_compile_writes_upload_files_provider_app_wrap with AttributeError: 'DynamicState' object has no attribute 'dynamic'; the remaining 18 upload-selected app tests pass with that case excluded.

@puneetdixit200 puneetdixit200 requested a review from a team as a code owner June 4, 2026 03:40
@greptile-apps

greptile-apps Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes issue #5290 by threading extra bound handler arguments through the full upload pipeline — from the Python EventHandler.__call__ compile step, through the JS client (uploadFiles / applyRestEvent), to the backend multipart parser and event dispatcher — for both buffered and streaming upload handlers.

  • Python (event/__init__.py): EventHandler.__call__ no longer returns immediately on a FileUpload arg; it collects remaining bound args into the event spec payload and appends a __reflex_event_arg_names manifest so the JS client knows which keys to forward.
  • JS (state.js, upload.js): applyRestEvent reads the manifest and passes the named args to uploadFiles, which serialises them as a __reflex_event_args JSON form field placed before file parts.
  • Backend (_upload.py): _UploadChunkMultipartParser gains an on_args_ready callback deferring handler dispatch until the args field is parsed; _decode_event_args validates the field is a JSON object (400 for malformed or non-object input).

Confidence Score: 5/5

Safe to merge; the fix is complete across all three layers and is well-covered by both unit and integration tests.

The change is a targeted, well-tested fix with no regressions on existing upload paths. The two findings are minor edge cases that do not affect real-world usage.

The pyproject.toml dev version specifier should be updated to a stable release version before shipping.

Important Files Changed

Filename Overview
packages/reflex-base/src/reflex_base/event/init.py Core fix: EventHandler.call now detects FileUpload args, defers returning, appends extra payload args to the upload EventSpec, and adds a __reflex_event_arg_names manifest. UPLOAD_EVENT_ARG_NAMES_KEY itself is not added to the reserved-clash set.
packages/reflex-base/src/reflex_base/.templates/web/utils/state.js applyRestEvent now reads the __reflex_event_arg_names manifest and passes the named args through to uploadFiles as extra_args.
packages/reflex-base/src/reflex_base/.templates/web/utils/helpers/upload.js uploadFiles gains an extra_args parameter and appends it as a JSON __reflex_event_args form field before file parts.
packages/reflex-components-core/src/reflex_components_core/core/_upload.py Backend: _UploadChunkMultipartParser gains on_args_ready callback; _decode_event_args validates JSON object; both buffered and streaming paths merge decoded args into the event payload.
tests/units/components/core/test_upload.py Comprehensive unit tests cover compile-time EventSpec structure, JSON decoding edge cases, buffered form arg parsing, and streaming parser behavior.
tests/integration/test_upload.py Integration tests extended to verify bound args reach both buffered and streaming handlers end-to-end.
packages/reflex-components-core/pyproject.toml Minimum reflex-base dependency bumped to a pre-release dev specifier; should be updated to a stable version before release.

Reviews (4): Last reviewed commit: "Bump reflex-base min dep to dev version" | Re-trigger Greptile

Comment thread packages/reflex-base/src/reflex_base/event/__init__.py Outdated
@puneetdixit200 puneetdixit200 force-pushed the fix/upload-bound-event-args branch from 22f9b26 to 9da7528 Compare June 4, 2026 05:17
@codspeed-hq

codspeed-hq Bot commented Jun 4, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 26 untouched benchmarks
⏩ 8 skipped benchmarks1


Comparing puneetdixit200:fix/upload-bound-event-args (704f674) with main (9972800)

Open in CodSpeed

Footnotes

  1. 8 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

FarhanAliRaza and others added 4 commits June 4, 2026 23:58
Args bound to an upload handler (e.g. State.on_drop(rx.upload_files(...),
field)) were preserved in the compiled event spec but never reached the
backend handler, since uploads travel over a REST endpoint instead of the
socket. The client now forwards the named extra args via a URL-encoded
JSON header, which the upload endpoint decodes and merges into the event
payload. Bound names that clash with reserved upload keys are rejected at
build time. Fixes reflex-dev#5290.
@puneetdixit200

Copy link
Copy Markdown
Contributor Author

The runtime upload path is covered on the current head now: the compiled event carries __reflex_event_arg_names, applyRestEvent forwards those keys to uploadFiles, uploadFiles sends them as Reflex-Event-Args, and the backend upload handlers merge that header into both buffered and chunk upload events.

Focused verification: uv run pytest tests/units/components/core/test_upload.py -k "upload_files_preserves_bound_event_args or upload_files_multiple_upload_args_raises or upload_files_bound_arg_reserved_name_raises" -q -> 3 passed, 12 deselected.

@FarhanAliRaza

Copy link
Copy Markdown
Contributor

@greptile please rereview.

Comment thread packages/reflex-components-core/src/reflex_components_core/core/_upload.py Outdated
Validate the reflex-event-args header before parsing form data so a
malformed or non-object JSON payload yields a 400 instead of a 500.
… them

Bound handler args were sent in a URL-encoded HTTP header, which the
streaming chunk parser never read, so chunked uploads dropped them and the
header path was capped by server limits. Move the args into a leading
__reflex_event_args multipart field parsed ahead of the first file chunk,
dispatching the handler once it is read. The field is size-bounded and
rejected if it arrives after a file part.
@FarhanAliRaza

Copy link
Copy Markdown
Contributor

@greptile please rereview.

FarhanAliRaza
FarhanAliRaza previously approved these changes Jun 5, 2026
masenf added 2 commits June 11, 2026 12:58
Indicate that reflex-components-core will depend tightly on the next public
release of reflex-base
@masenf masenf merged commit 7562344 into reflex-dev:main Jun 12, 2026
106 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot pass additional arguments to rx.upload on_drop handler

3 participants