Show inner `"use cache"` as cause of nested-dynamic cache error (#93707)
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.
<img width="2188" height="2662"
alt="localhost_3000_use-cache-low-expire_nested (1)"
src="https://github.com/user-attachments/assets/f5103e0e-b9c0-44c5-b93b-82981aa05219"
/>