You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
popup: a destination slower than the 5 s claim window leaves the ceremony waiting #78
When a popup document hands its port to the Service Worker during a navigation ("keep"), the worker holds it for the next document to claim, for at most 5 s (CARRIER_CLAIM_TIMEOUT_MS, keeper.ts:15). If nothing claims it in time, the worker closes the port without telling anyone (worker.ts:72-79).
The application cannot notice. A closed MessagePort is not observable in Firefox or Safari, and while it holds a carrier the application skips its window check, because a COOP navigation severs the window handle even though the popup is alive (connection.ts:354-380). ClientCeremony settles only when the connection ends (ceremony.ts:195), so proveUserIdentity() never settles. The late document finds no port to claim and fails, but it has no channel to the application, so the failure reaches only its own console (failure.ts:36).
When it happens
A slow destination document. In Firefox and Safari every Prover keeps its port and hops to the COOP isolation fallback, which must load and claim within 5 s.
Closing the popup mid-hop reaches the same silent expiry without any slow document; that case and its fix are #82.
Current assumption
5 s is enough to load a CCDP document, and this has held in practice across the devices tested. So the slow-document case is not expected today.
Mitigation for slow documents
Prefetch the destination documents, such as the isolation fallback, like any other asset, so the hop loads from the worker's cache well within the claim window. Not needed today, since the assumption holds. #82's fix would also turn an expiry here into a prompt failure instead of a hang.
changed the title [-]popup: a kept port that expires before its claim leaves the ceremony waiting[/-][+]popup: a destination slower than the 5 s claim window leaves the ceremony waiting[/+]on Oct 2, 2026
The "current assumption" above no longer covers Safari. WebKit sometimes never commits a navigation that switches browsing context group (COOP): https://bugs.webkit.org/show_bug.cgi?id=327297, found through #121. The Prover's hop to its COOP isolation fallback is exactly that kind of navigation, so the hop can stall with no slow document involved:
WebKit recovers after the 5 s claim window. The fallback loads and finds the port expired. It has no opener and no fallback carrier, so it fails, and the application keeps waiting. That is this issue.
WebKit never recovers. The fallback never loads, and the application waits for the same reason.
Either way the kept port expires unclaimed, so #82's proposed carrier-expired control would turn both into a prompt popup-unavailable failure. Prefetching the fallback document would not help here, because the stall isn't load time.
We looked at re-issuing the stalled navigation from the popup and rejected it. On #121's test under load it doubled the failures, because it restarts hops that are only slow and lets the claim window lapse.
Correction to my comment above: #82 covers only the first outcome.
WebKit commits late: the fallback moves to a new browsing context group, so the application's handle reports closed (severed), and carrier-expired would fail it promptly.
Re-issuing location.replace() does unstick a stalled document: in the plain repro on the WebKit bug, a 3 s retry got 10/10 runs through 200 hops. It failed on #121 only because the destination must claim the kept port within 5 s. I'm trying a version that keeps the port while the departing document is still alive and retries the navigation with backoff, so a retry can't cost the port.
Activity
[-]popup: a kept port that expires before its claim leaves the ceremony waiting[/-][+]popup: a destination slower than the 5 s claim window leaves the ceremony waiting[/+]Wondertan commentedon Oct 12, 2026
The "current assumption" above no longer covers Safari. WebKit sometimes never commits a navigation that switches browsing context group (COOP): https://bugs.webkit.org/show_bug.cgi?id=327297, found through #121. The Prover's hop to its COOP isolation fallback is exactly that kind of navigation, so the hop can stall with no slow document involved:
Either way the kept port expires unclaimed, so #82's proposed
carrier-expiredcontrol would turn both into a promptpopup-unavailablefailure. Prefetching the fallback document would not help here, because the stall isn't load time.We looked at re-issuing the stalled navigation from the popup and rejected it. On #121's test under load it doubled the failures, because it restarts hops that are only slow and lets the claim window lapse.
Wondertan commentedon Oct 13, 2026
Correction to my comment above: #82 covers only the first outcome.
carrier-expiredwould fail it promptly.Re-issuing
location.replace()does unstick a stalled document: in the plain repro on the WebKit bug, a 3 s retry got 10/10 runs through 200 hops. It failed on #121 only because the destination must claim the kept port within 5 s. I'm trying a version that keeps the port while the departing document is still alive and retries the navigation with backoff, so a retry can't cost the port.fix(popup): navigate again when WebKit stalls a hop, keeping its port
fix(popup): navigate again when WebKit stalls a hop, keeping its port
fix(popup): navigate again when WebKit stalls a hop, keeping its port
fix(popup): navigate again when WebKit stalls a hop, keeping its port