← Back to microsoft/playwright
microsoft / playwright · Issue No. 42823
1.62.1
The attachment contains sources, instructions and already-recorded evidence. The portable extraction, including this supplemented submission copy, has not been executed. The observations below came from the original local benches from which these sources were extracted. No new execution was performed to prepare this report.
next/link prefetch at its default (the prefetch prop is undefined). Keep the synthetic control file at {"arm":"A"} in both routing arms./c/synthetic/sacramentos with waitUntil: "domcontentloaded"; verify the synthetic heading and link are visible.RSC: 1, Next-Router-Prefetch: 1, and no corresponding completion/failure yet.page.goto to /c/synthetic/catequese. Verify its URL and synthetic headings. Collect events for three seconds after the destination assertions. Responses are not delayed and requests are not fabricated.The synchronization in step 4 is diagnostic and can affect timing. It is not a proposed application workaround or a functional-test wait.
Expected: a hard navigation can cancel obsolete prefetches, while the destination remains usable. We expected no unexplained access-control pageerrors and correct distinction between intentional cancellation and a genuine fetch failure. Please clarify the applicable lifecycle contract if that expectation is incorrect.
A small synthetic Next.js production app reproduces five cancelled prefetch requests, nine RSC fallback console errors and four Playwright pageerror events when a second page.goto starts while automatic prefetch is pending. The destination page loads and its content assertions pass, but the diagnostic records consoleGuardPassed=false. These standalone observers returned exit code zero for completed collection; this was not a passing E2E runner result.
We are requesting help triaging the interaction between WebKit navigation, Playwright request interception and Next.js prefetch lifecycle. Attribution remains open; this report does not establish a Playwright-only defect.
Observed in each of two later routing arms, executed once:
| Observation | A: local requests handled | B: local requests skip user handler |
|---|---|---|
| Prefetch pending when navigation started | Yes | Yes |
| Local HTTP handler entries | 28 | 0 |
| Cancelled prefetch requests | 5 | 5 |
| RSC fallback console errors | 9 | 9 |
| pageerror events | 4 | 4 |
| Destination prefetches subsequently completed | 9 | 9 |
| Expected destination URL/content | Present | Present |
Diagnostic consoleGuardPassed |
false | false |
Representative messages (query strings omitted here):
Load request cancelled
Failed to fetch RSC payload for https://127.0.0.1:3199/login Falling back to browser navigation. TypeError: Load failed
Fetch API cannot load https://127.0.0.1:3199/login due to access control checks.
The four access-control messages refer to /login, /register, /c/synthetic/catequese and /c/synthetic/catequese/acolhimento. They lack corresponding browser request events in the captured evidence. The message alone does not establish a CORS configuration defect or an unhandled JavaScript promise.
Arm A uses context.route('**/*', handler). Arm B uses context.route(url => !allowedOrigin(url), handler), with the same allowed HTTPS loopback origin. Thus B bypasses the user handler for local HTTP requests; it does not disable Playwright's internal interception. Both arms also block WebSockets; none are used by the pages.
Inspection of the installed WebKit adapter shows routing enables Network.setInterceptionEnabled, disables HTTP caching, and registers a global interception pattern. Unmatched requests are continued internally. Removing the local handler did not eliminate the signature, but there is no routing-disabled control. B also omits A's method/credential checks for local traffic; these synthetic runs recorded only allowed GET/HEAD traffic, zero cookies and zero blocked external destinations.
An earlier instrumented-Next session recorded two distinct timelines (UTC):
abortController.signal.aborted=false, followed by pagehide at .833. The catches have document sequence numbers 178 through 194; pagehide is 195. These sequence numbers establish catch-before-pagehide within that document; the Node events are not part of that sequence.Next 15.5.19 already aborts its controller on pagehide, recreates it on pageshow, and suppresses the fallback log when the signal is aborted. In this recording, the catches ran before that suppression condition became true. This explains when the logs were emitted, not the native cause of the failures.
The later A/B used Next without these internal probes and reproduced the same counts. It did not remeasure the signal. In A, user continue() calls resolved before the requestfailed events, but this does not prove wire delivery. The five cancelled requests have no correlated HTTP receipt in the proxy/Next records; the four later fetch errors have no corresponding browser request event. Subsequent destination prefetches were correlated and completed with HTTP 200.
No HTTP 5xx was recorded during either arm; a startup 502 preceded readiness and both arms. Cross-process timestamp order alone is not a causal proof. Instrumentation, routing, TLS, diagnostic synchronization, and server warming between A and B remain limitations. No proxy defect, browser defect, or Next defect has been isolated. No route-free run was performed, and no console error has been treated as harmless or filtered out.
Does WebKit's Playwright navigation/interception path permit this cancellation-before-pagehide ordering, and what distinguishes it from native navigation? How can the four fetch refusals that have no request ID be attributed to document teardown versus a security check? Is there a known, specific lifecycle or interception fix that matches this signature?
The attachment includes the synthetic sources, the earlier observation-only Next patch and license, both later observations and HTTP correlation records. We have not updated dependencies, patched application behavior, or run repeated attempts until success.
Proposed attachment: next-webkit-repro-submission-final.zip. Its README separates the instrumented historical configuration from the later uninstrumented routing comparison. This is a source-and-evidence package for triage, not a self-contained or runtime-validated distribution: exact dependencies, the browser binary and a synthetic TLS certificate must be supplied separately; no resolved lockfile is included.
next-webkit-repro-submission-final.zip
The output of npx envinfo --preset playwright was not recorded. The following is the recorded environment, not generated envinfo output.
OS: Windows; exact edition, OS build and native architecture were not recorded in the selected evidence
Node.js: 24.16.0
Next.js: 15.5.19, App Router, production build
React / React DOM: 19.2.7 / 19.2.7
@playwright/test / playwright-core: 1.62.1 / 1.62.1
Browser: Bundled WebKit 26.5, revision 2336; headless
Context: Desktop Safari device descriptor; viewport 1280 x 720; new context per arm; service workers blocked
Transport: HTTPS https://127.0.0.1:3199 through a Node proxy to HTTP 127.0.0.1:3200
TLS: Temporary synthetic certificate; ignoreHTTPSErrors=true in the isolated browser context
No database, application business modules, authentication, cookies or external services are required. The device descriptor's user agent must not be used to infer the host OS. These are recorded versions, not a claim that they are the latest releases.
Relay reads this issue against the repository's contribution signals: the files it is likely to touch, how the maintainers triage work this size, and what the first contribution would exercise.
The full analysis for this issue is still being assembled. Until then, the description above and the thread on GitHub are the most reliable context.