Show inner "use cache" as cause of nested-dynamic cache error#93707
Open
unstubbable wants to merge 1 commit intohl/do-not-throw-invalid-dynamic-usage-errors-in-devfrom
Open
Show inner "use cache" as cause of nested-dynamic cache error#93707unstubbable wants to merge 1 commit intohl/do-not-throw-invalid-dynamic-usage-errors-in-devfrom
"use cache" as cause of nested-dynamic cache error#93707unstubbable wants to merge 1 commit intohl/do-not-throw-invalid-dynamic-usage-errors-in-devfrom
Conversation
Contributor
Author
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
Contributor
Tests PassedCommit: ff34f00 |
b1a9438 to
74aad9e
Compare
Contributor
Stats from current PR🔴 1 regression
📊 All Metrics📖 Metrics GlossaryDev Server Metrics:
Build Metrics:
Change Thresholds:
⚡ Dev Server
📦 Dev Server (Webpack) (Legacy)📦 Dev Server (Webpack)
⚡ Production Builds
📦 Production Builds (Webpack) (Legacy)📦 Production Builds (Webpack)
📦 Bundle SizesBundle Sizes⚡ TurbopackClient Main Bundles
Server Middleware
Build DetailsBuild Manifests
📦 WebpackClient Main Bundles
Polyfills
Pages
Server Edge SSR
Middleware
Build DetailsBuild Manifests
Build Cache
🔄 Shared (bundler-independent)Runtimes
📝 Changed Files (8 files)Files with changes:
View diffsapp-page-exp..ntime.dev.jsfailed to diffapp-page-exp..time.prod.jsDiff too large to display app-page-tur..ntime.dev.jsfailed to diffapp-page-tur..time.prod.jsDiff too large to display app-page-tur..ntime.dev.jsfailed to diffapp-page-tur..time.prod.jsDiff too large to display app-page.runtime.dev.jsfailed to diffapp-page.runtime.prod.jsDiff too large to display 📎 Tarball URLCommit: ff34f00 |
When a `"use cache"` propagated a dynamic cache life (`revalidate: 0` or `expire` under 5 minutes) to a parent without an explicit `cacheLife`, the resulting error pointed only at the outer cache invocation. With the inner cache's call site missing, tracing which nested cache was responsible meant reading through the outer's body — fine when it's local code, much harder when the dynamism comes from a nested cache buried in a third-party dependency. This change attaches the inner invocation as `cause` of the error, so the dev redbox and the build log show two stacks: the outer that threw, and the inner that propagated the dynamic life. The inner call site has to be captured eagerly while `cache()` is still on the synchronous stack, because we only learn whether the inner resolved dynamic asynchronously — after `collectResult` finishes and `propagateCacheEntryMetadata` runs — and by then the inner's frames are no longer on the JS stack. We only construct the eager `Error` when the parent is itself a public `"use cache"` (the only case where this entry could become a propagated origin), so top-level caches skip the allocation. The eager `Error` is held on `cacheContext.dynamicNestedCacheError`; once propagation knows the inner resolved dynamic, it's copied onto the outer store's same-named field, then carried through the outer's own `collectResult` into its RDC entry — which the throw site finally reads back as `cause`. We keep the first dynamic child — the immediate origin from the throwing cache's perspective. The two nested-dynamic cache error messages also get a small cleanup: each used to write `"use cache"` two different ways within the same sentence (bare and backticked); both now write it the same way.
74aad9e to
ff34f00
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.

When a
"use cache"propagated a dynamic cache life (revalidate: 0orexpireunder 5 minutes) to a parent without an explicitcacheLife, the resulting error pointed only at the outer cache invocation. With the inner cache's call site missing, tracing which nested cache was responsible meant reading through the outer's body — fine when it's local code, much harder when the dynamism comes from a nested cache buried in a third-party dependency.This change attaches the inner invocation as
causeof the error, so the dev redbox and the build log show two stacks: the outer that threw, and the inner that propagated the dynamic life.The inner call site has to be captured eagerly while
cache()is still on the synchronous stack, because we only learn whether the inner resolved dynamic asynchronously — aftercollectResultfinishes andpropagateCacheEntryMetadataruns — and by then the inner's frames are no longer on the JS stack. We only construct the eagerErrorwhen the parent is itself a public"use cache"(the only case where this entry could become a propagated origin), so top-level caches skip the allocation. The eagerErroris held oncacheContext.dynamicNestedCacheError; once propagation knows the inner resolved dynamic, it's copied onto the outer store's same-named field, then carried through the outer's owncollectResultinto its RDC entry — which the throw site finally reads back ascause. We keep the first dynamic child — the immediate origin from the throwing cache's perspective.The two nested-dynamic cache error messages also get a small cleanup: each used to write
"use cache"two different ways within the same sentence (bare and backticked); both now write it the same way.