Please provide the environment you discovered this bug in.
Analog v3 alpha, Angular 22.1.5, Vite 8.2.2, Nitro 3.0.260903-beta, Node 24.15.0, and pnpm 10.33.0 on Linux.
Public regression commit contains the failing tests and greeting-page browser example before the lifecycle repairs. It is based on the separately prepared compiler, Vitest, SSR, and HTTP prerequisites from #2516.
git clone https://github.com/benpsnyder/analog.git
cd analog
git checkout 94f601181
corepack enable
pnpm install --frozen-lockfile
CI=true NX_DAEMON=false NX_NO_CLOUD=true pnpm exec nx run router:test --testFile=dispatch-lifecycle.spec.ts,client-lifecycle.spec.ts,page-load-hydration.spec.ts,cookie-interceptor.spec.ts,request-context.spec.ts,provide-analog-query.spec.ts,server-query.spec.ts --skip-nx-cache
CI=true NX_DAEMON=false NX_NO_CLOUD=true pnpm exec nx run platform:test --testFile=ssr-request-context.spec.ts
pnpm exec playwright install chromium
CI=true NX_DAEMON=false NX_NO_CLOUD=true pnpm exec nx run analog-app-e2e:e2e --grep='hydrates the native load' --retries=0
Use the .node-version pin. The three regression commands are expected to fail before the repair; run them independently.
Which area/package is the issue in?
router, platform
Description
The existing greeting example renders its data on the server, but the browser then requests the same load again. Adding a custom route resolver that calls getLoadResolver produces two identical browser load requests during hydration. Later query changes need one fresh load shared by the native and custom resolvers.
Related lifecycle regressions affect the same request-to-hydration path:
- Child server-function injectors survive completed or failed calls, including buffered
Response consumption.
- Superseded/destroyed resources and cancelled Query observers leave HTTP subscriptions active. Aborted in-process calls can still supply stale hydration results.
null and input-less server-function reads share a hydration key. Native page-load hydration does not preserve and consume its transferred value across supported falsy/undefined results.
- TanStack's selected cache and Analog/Angular HTTP transfer caches can disagree. An older child payload can replace fresher parent/application data in the serialized state, despite the live Query cache retaining the newer value.
- The SSR fetch adapter is not bound to the incoming request's headers, cancellation, and runtime context. Automatic credential forwarding needs a local-endpoint boundary and explicit child headers must take precedence.
The use case is two overlapping page requests with distinct synthetic credentials, followed by browser hydration and a query-changing navigation. Each render should retain its own request context; hydration should make no duplicate load; subsequent navigation should fetch fresh data and cancel obsolete reads.
Expected behavior:
- Release child request scopes after success/failure and response-body consumption, retaining application-owned services.
- Forward cancellation to browser subscriptions and suppress stale in-process results without claiming to interrupt arbitrary handler work or undo mutations.
- Consume hydration seeds once, retain full endpoint/query identity, and share one native load promise per route snapshot.
- Preserve the data selected by TanStack's timestamp rules and use its dehydrated state as the Query cache owner.
- Bind SSR fetch to the current request; automatically forward credentials only to local endpoints and retain explicit overrides.
Please provide the exception or error you saw
Baseline results: 36 router test failures and eight SSR request-context failures. The browser regression observes these two requests after server-rendered content has already arrived:
Expected: []
Received:
/api/_analog/pages/greet/reader?shout=false
/api/_analog/pages/greet/reader?shout=false
The focused tests also record missing request-scope destruction, uncancelled subscriptions, stale hydration/cache values, and missing request-scoped fetch properties. Fixtures use synthetic data only.
Other information
Workstream 5 from Brandon Roberts' requested split. Transport/registration is tracked separately in analogjs/analog#2524; progressive streaming remains a separate contribution.
The focused fix is published in analogjs/analog#2530, targeting alpha. Current head 1d89179bc62d1ce07afc979ec9e9f9bfad99ee27 passes the dedicated lifecycle runtime workflow, main/application E2E, Windows, and preview CI. Package tests, real browser hydration/navigation coverage, and positive/negative installed-package type tests are documented in the PR. The latest full local application E2E run passed 37 tests with two existing skips. The failing reproduction above remains pinned; this issue stays open pending merge.
I would be willing to submit a PR to fix this issue
Please provide the environment you discovered this bug in.
Analog v3 alpha, Angular 22.1.5, Vite 8.2.2, Nitro 3.0.260903-beta, Node 24.15.0, and pnpm 10.33.0 on Linux.
Public regression commit contains the failing tests and greeting-page browser example before the lifecycle repairs. It is based on the separately prepared compiler, Vitest, SSR, and HTTP prerequisites from #2516.
Use the
.node-versionpin. The three regression commands are expected to fail before the repair; run them independently.Which area/package is the issue in?
router, platform
Description
The existing greeting example renders its data on the server, but the browser then requests the same load again. Adding a custom route resolver that calls
getLoadResolverproduces two identical browser load requests during hydration. Later query changes need one fresh load shared by the native and custom resolvers.Related lifecycle regressions affect the same request-to-hydration path:
Responseconsumption.nulland input-less server-function reads share a hydration key. Native page-load hydration does not preserve and consume its transferred value across supported falsy/undefined results.The use case is two overlapping page requests with distinct synthetic credentials, followed by browser hydration and a query-changing navigation. Each render should retain its own request context; hydration should make no duplicate load; subsequent navigation should fetch fresh data and cancel obsolete reads.
Expected behavior:
Please provide the exception or error you saw
Baseline results: 36 router test failures and eight SSR request-context failures. The browser regression observes these two requests after server-rendered content has already arrived:
The focused tests also record missing request-scope destruction, uncancelled subscriptions, stale hydration/cache values, and missing request-scoped fetch properties. Fixtures use synthetic data only.
Other information
Workstream 5 from Brandon Roberts' requested split. Transport/registration is tracked separately in analogjs/analog#2524; progressive streaming remains a separate contribution.
The focused fix is published in analogjs/analog#2530, targeting
alpha. Current head1d89179bc62d1ce07afc979ec9e9f9bfad99ee27passes the dedicated lifecycle runtime workflow, main/application E2E, Windows, and preview CI. Package tests, real browser hydration/navigation coverage, and positive/negative installed-package type tests are documented in the PR. The latest full local application E2E run passed 37 tests with two existing skips. The failing reproduction above remains pinned; this issue stays open pending merge.I would be willing to submit a PR to fix this issue