[BUGFIX] @model becomes undefined or changes to the wrong route's model during Glimmer component willDestroy#21203
Open
johanrd wants to merge 6 commits intoemberjs:mainfrom
Open
[BUGFIX] @model becomes undefined or changes to the wrong route's model during Glimmer component willDestroy#21203johanrd wants to merge 6 commits intoemberjs:mainfrom
@model becomes undefined or changes to the wrong route's model during Glimmer component willDestroy#21203johanrd wants to merge 6 commits intoemberjs:mainfrom
Conversation
When transitioning between routes, the @model argument on a Glimmer component becomes unstable during willDestroy - the model value changes before the component is properly destroyed. Requires @glimmer/component Vite alias to resolve in tests. Based on PR emberjs#20959 by @Windvis.
When transitioning between routes, @model becomes undefined in Glimmer component willDestroy hooks. The existing guard (lastState === state) only detects outlet changes at the same level. When a parent outlet tears down first, the dynamic scope refs silently redirect to the new route's outlet state while the guard still passes. Add a controller identity check so the model ref detects when its outletRef has been redirected to a different route's data. Fixes emberjs#18987
…nternal @glimmer/component import isn't necessary in vite.config
NullVoxPopuli
approved these changes
Mar 8, 2026
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.
Summary
@modelbecomesundefined(or changes to the wrong route's model) during Glimmer componentwillDestroywhen transitioning between routeslastState === stateguard in the outlet helper's model compute ref@modelis stable between route transitions #20959 by @Windvis)Details
The
@modelreference in route templates is built from a chain of compute refs that read from the shared outlet state tree via dynamic scope. When transitioning,_setOutlets()rebuilds this tree, and all refs in the chain immediately see the new state.The existing guard (
lastState === state) freezes the model value when the outlet changes at the same level. But when a parent outlet is torn down first, the child outlet's outer compute ref never re-evaluates, solastStateis never updated. The guard passes, andmodelRefreads from the wrong outlet state.The fix compares the current outlet's controller identity against the expected one. Since each route has a unique controller singleton, this detects when the
outletRefhas been redirected — even whenlastStatehasn't been updated yet.From git history, the bug may have existed since
@modelwas introduced in v3.14.0 (16b74a5). The original implementation read directly from theoutletRefchain with no guard at all. ThelastState === stateguard added in v4.0.0 (commit 7d334cf) partially mitigated same-level transitions but did not catch parent-level teardown.Fixes #18987
Supersedes #20959
Test plan
smoke-tests/scenarios/basic-test.ts: transitions through sibling, parent, cousin, and unrelated routes, verifyingthis.args.modelinwillDestroyBased on Add a test that verifies@modelis stable between route transitions #20959 but moved to smoke-test to avoid the vite.config import of glimmer-componentBefore the fix, the added smoke tests fail with:
workspace:*(with fix)~6..11.0~5.12.0~4.0.0~3.28.0Cowritten by claude