Fast renderer: do not lose handler and cleanup errors - #64
Merged
Merged
Conversation
An audit of REACTON_FAST=1 against the default renderer (fuzzing both renderers, solara's test suite, and a production app) found fast-only bugs that the default renderer does not have: - An event handler exception raised while another thread renders was lost: force_update only set a flag that the running render cleared, and no path to the component was marked, so later renders skipped it. - An effect cleanup exception during unmount was lost, and closed widgets stayed on screen: marking the ancestors stopped at a stale flag inside the subtree being removed, so the live ancestors were never marked. Walking to the root costs only the tree depth. - The fix for a replaced parent widget did not cover a widget replaced by a shared component element, whose arguments are rendered in the same context: that still crashed with a KeyError. Both now share one helper. The default renderer is unchanged by this; the new tests run in both modes in CI and fail on the fast renderer without the fix. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
maartenbreddels
force-pushed
the
fix/fast-lost-errors-and-flip-crash
branch
from
September 28, 2026 16:00
27b14f4 to
eeda41a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
We want to turn on
REACTON_FAST=1in production, so we audited the fast renderer against the default renderer: a line-by-line review, a fuzzer that compares both renderers (about 18,000 random trees), solara 1.60.2's test suite in both modes, and a production app's test suite. This PR fixes the remaining fast-only bugs that matter. The default renderer is unchanged.Rebased on #63, which fixed the crash for a replaced parent widget in the same way. This PR is now smaller.
Fixes
on_click,use_event) that raised while another thread was rendering lost its exception.force_update()only set a flag that the running render then cleared, and nothing marked the path to the component, so later renders skipped it. The handler now marks the ancestors, the same way a state setter does.use_exceptionreplaced a subtree) lost its exception, and closed widgets stayed on screen. Marking the ancestors stopped at a stale flag inside the subtree being removed. It now always walks up to the root, which costs only the tree depth..shared()component element. Its arguments are rendered in the same context, so it still raisedKeyError. Widget arguments and shared-element arguments now go through one helper (_render_arguments), which uses the_replacingcounter from Fuzz the fast renderer against the default one, and fix the KeyError it finds #63.Tests
core_test.py. CI runs them withREACTON_FAST=0and=1. All three pass on the default renderer. On current master they fail on the fast renderer.Astra (GPT-6) reviewed the version before the rebase and approved it, with nothing blocking.
Not in this PR
These fast-mode differences remain, and are deliberate or rare:
on_<trait>handler are no longer reset by unrelated renders.force_update()no longer re-applies element kwargs.A keyed child that moves out of a parent that is being replaced shows a closed widget in both renderers. That is a separate bug.
🤖 Generated with Claude Code