Skip to content

Fix _get_all_hooks_internal mutating the shared per-node hooks cache#6741

Open
Alek99 wants to merge 2 commits into
mainfrom
claude/reflex-perf-optimizations-01l7a3-eng-10108
Open

Fix _get_all_hooks_internal mutating the shared per-node hooks cache#6741
Alek99 wants to merge 2 commits into
mainfrom
claude/reflex-perf-optimizations-01l7a3-eng-10108

Conversation

@Alek99

@Alek99 Alek99 commented Jul 10, 2026

Copy link
Copy Markdown
Member

Linear: ENG-10108

Description

Component._get_all_hooks_internal called .update() directly on the dict returned by _get_hooks_internal(), which is the node's cached _hooks_internal_cache. Collecting hooks for a subtree therefore permanently polluted every intermediate node's cache with its descendants' hooks. The same cached dict was further mutated through |= in Bare._get_all_hooks_internal.

Consequences of the pollution:

  • Hook collection became order-dependent: whichever traversal ran first baked descendant hooks into ancestors' caches, so memo tag hashes over internal hooks (_update_deterministic_hash) could differ for otherwise-identical subtrees, defeating memo dedup.
  • Per-node hook queries (_get_hooks_internal) returned descendants' hooks, duplicating hooks into memo bodies and skewing subtree reactivity classification.

Fix: copy the cached dict before merging children's hooks into it. Bare's |= then mutates the fresh copy returned by super(), so it needs no change.

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?
    • tests/units/components/test_component.py::test_get_all_hooks_internal_does_not_mutate_hooks_cache: asserts subtree collection includes both nodes' hooks while each node's own cache stays unpolluted, and that repeated collection is stable. Fails before this fix.
  • Have you successfully ran tests with your changes locally?

🤖 Generated with Claude Code

https://claude.ai/code/session_01G8cXh3TUbNtbjm2ERqE62X


Generated by Claude Code

_get_all_hooks_internal called .update() directly on the dict returned
by _get_hooks_internal, which is the node's cached _hooks_internal_cache.
Walking a tree therefore polluted every node's cache with its
descendants' hooks, making hook collection order-dependent: memo tag
hashes over internal hooks could differ for identical subtrees
(defeating dedup) and per-node hook queries returned descendant hooks.

Copy the cached dict before merging children's hooks into it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G8cXh3TUbNtbjm2ERqE62X
@Alek99 Alek99 requested a review from a team as a code owner July 10, 2026 20:06
@linear-code

linear-code Bot commented Jul 10, 2026

Copy link
Copy Markdown

ENG-10108

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G8cXh3TUbNtbjm2ERqE62X
@codspeed-hq

codspeed-hq Bot commented Jul 10, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 26 untouched benchmarks
⏩ 8 skipped benchmarks1


Comparing claude/reflex-perf-optimizations-01l7a3-eng-10108 (c537b61) with main (9a5c4d3)

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.

@greptile-apps

greptile-apps Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes internal hook collection so subtree hooks no longer mutate per-node caches.

  • Copies the cached internal hook dict before merging child hooks.
  • Adds a regression test for cache isolation and repeated collection stability.
  • Adds a bugfix news fragment for the hook-cache pollution fix.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.
  • The hook collection change isolates mutation while preserving the same dict contents for callers.
  • The added test covers the cache pollution behavior described by the fix.

Important Files Changed

Filename Overview
packages/reflex-base/src/reflex_base/components/component.py Copies _get_hooks_internal() before merging descendants in _get_all_hooks_internal, avoiding mutation of the cached per-node hooks.
tests/units/components/test_component.py Adds a focused test that verifies subtree hook collection does not pollute the parent's own hook cache.
packages/reflex-base/news/6741.bugfix.md Adds a news entry describing the internal hook-cache pollution fix.

Reviews (1): Last reviewed commit: "Add changelog fragment" | Re-trigger Greptile

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.

2 participants