Content
View differences
Updated by Alexander Coles 3 days ago
> _This *This was generated by AI during triage._ triage.*
## Problem
The global `turbo:frame-missing` handler unconditionally visits the failed response URL. When a page shell loads successfully but its lazy Turbo frame consistently fails, this recovery can create an infinite page reload loop.
This was observed while investigating [AGILE-434](https://community.openproject.org/wp/AGILE-434). The milestone filter caused a database error in the Backlogs frame request. Fixing that query removes one trigger, but leaves the shared recovery defect in place.
## Steps to reproduce
1. On an affected 17.9 build, open a project's project's Backlogs page with the Is milestone filter available.
2. Open All filters and add Is milestone.
3. The `backlogs_container` request fails with HTTP 500 and a response without the expected frame.
4. Observe the page repeatedly reconstructing on staging.
For a regression test independent of the milestone query, use a page whose shell returns HTTP 200 and contains a lazy frame whose endpoint consistently returns HTTP 500 without the expected frame.
## Actual behavior
1. The failed frame response raises `turbo:frame-missing`.
2. The global handler prevents the default behavior and calls `visit(response.url, {})`.
3. The full-page request renders the page shell successfully.
4. Its lazy frame makes the same failing request, restarting the cycle.
The original error is obscured by repeated navigation, the page becomes unusable, and additional requests continue without user input.
## Expected behavior
* - A failed frame request terminates in a stable, understandable error state.
*
- The application does not automatically revisit the same failing page or repeat requests indefinitely.
*
- Users can recover through an explicit action without losing the rest of the usable page unnecessarily.
*
- Successful frame navigation and any intentional full-page redirects continue to work.
## Technical context
The unconditional fallback is in [frontend/src/turbo/setup.ts](https://github.com/opf/openproject/blob/release/17.9/frontend/src/turbo/setup.ts), in the `turbo:frame-missing` listener.
Remove the unconditional automatic revisit and determine the appropriate error presentation using the existing Turbo/application conventions. Review affected callers, including intentional redirects such as authentication flows, before removing shared behavior.
Add regression coverage for a consistently failing lazy frame, a successful response missing the expected frame, and supported intentional navigation. Assert that requests stop and that the page remains in a stable state.
## Evidence and scope
Observed during investigation on 2026-09-15. Local `release/17.9` at `9a0c3fd503e38abd33fbaeeaf934a3bad9360e4d` reproduced the initiating HTTP 500 (`PG::AmbiguousColumn`); staging demonstrated repeated page reconstruction. Local development renders a different exception response, so the full production-style loop was not reproduced identically there.
This is a separate Bug in shared error recovery. The Backlogs SQL repair in #AGILE-434 AGILE-434 and the other Backlogs filter fixes remain independent. No target version is proposed here.
## Problem
The global `turbo:frame-missing` handler unconditionally visits the failed response URL. When a page shell loads successfully but its lazy Turbo frame consistently fails, this recovery can create an infinite page reload loop.
This was observed while investigating [AGILE-434](https://community.openproject.org/wp/AGILE-434). The milestone filter caused a database error in the Backlogs frame request. Fixing that query removes one trigger, but leaves the shared recovery defect in place.
## Steps to reproduce
1. On an affected 17.9 build, open a project's
## Actual behavior
1. The failed frame response raises `turbo:frame-missing`.
## Expected behavior
*
*
-
*
-
*
-
The unconditional fallback is in [frontend/src/turbo/setup.ts](https://github.com/opf/openproject/blob/release/17.9/frontend/src/turbo/setup.ts), in the `turbo:frame-missing` listener.
Remove the unconditional automatic revisit and determine the appropriate error presentation using the existing Turbo/application conventions. Review affected callers, including intentional redirects such as authentication flows, before removing shared behavior.
Add regression coverage for a consistently failing lazy frame, a successful response missing the expected frame, and supported intentional navigation. Assert that requests stop and that the page remains in a stable state.
## Evidence and scope
Observed during investigation on 2026-09-15. Local `release/17.9` at `9a0c3fd503e38abd33fbaeeaf934a3bad9360e4d` reproduced the initiating HTTP 500 (`PG::AmbiguousColumn`); staging demonstrated repeated page reconstruction. Local development renders a different exception response, so the full production-style loop was not reproduced identically there.
This is a separate Bug in shared error recovery. The Backlogs SQL repair in #AGILE-434