Skip to content

playwright protocol error page navigate

github-actions[bot] edited this page Aug 30, 2026 · 1 revision

Playwright "Protocol Error (Page.navigate)"

Page.navigate is not a Chromium-only string. It is the internal channel-and-method name Playwright's own driver uses for a navigation command, and reports of it firing verbatim show up against Chromium and Firefox alike: one regression report tracking a 1.53.2-to-1.54.0 break names the failure on browser.newContext before a single page even opens, and another, older regression naming the same string is filed as affecting "Chromium and Firefox" together. This is a Playwright-internal transport error, not a browser-engine one, which is the opposite of most protocol strings that reach the surface with an engine's name already stamped on them.

That distinction matters because it is easy to read Page.navigate as CDP jargon and go looking for a Chromium net-stack explanation that does not apply here.

How this differs from TargetClosedError

TargetClosedError is what you get when the thing Playwright was talking to is already gone: the call goes out, there is nothing left on the other end to answer it, and the client reports the disconnection. A Protocol error (Page.navigate): <reason> is a different point in the same pipe. The call went out, a response came back, and the response was a refusal naming a specific reason. The target did not vanish. The navigate command itself was rejected.

In practice the two can sit right next to each other in a stack trace, because a rejected navigate can be the thing that then closes the context around it. Read the text after the colon before assuming either one. If it names an invalid URL, treat it as this page. If it says nothing more specific than "closed," it belongs on the TargetClosedError page instead, whose three Firefox and Juggler causes are a different diagnosis entirely.

Cause 1: the URL you actually sent was invalid

Verbatim symptom:

Error: page.goto: Protocol error (Page.navigate): Cannot navigate to invalid URL

This is the most literal reading and the most common one. page.goto(""), a relative path with no baseURL configured to resolve it against, or a string that never was a URL (an empty template interpolation, a None serialized to text) all produce the identical rejection. The browser is not being picky; an empty string or a bare path segment is not a URL by any standard, and both engines refuse it identically.

How to confirm it: print the exact value handed to goto() immediately before the call. Not the variable you believe holds it, the value at the call site. This alone resolves most reports of this cause, because the mismatch between "what I thought I sent" and "what actually left the process" is the whole bug.

Cause 2: Playwright's own client built the invalid URL for you

This is the less obvious variant, and it is worth knowing about specifically because it looks identical to cause 1 while the fix is different. A baseURL set in configuration gets combined with whatever you pass to goto() using URL-construction rules, and a regression tracked between Playwright 1.53.2 and 1.54.0 shows exactly this: a plain await page.goto('/') that had worked started failing with Error: browser.newContext: Protocol error (Page.navigate): Cannot navigate to invalid URL after a change in how that combination was resolved internally, with no change to the calling code. A second, older regression between 1.38 and 1.39 hit the same string only inside a custom worker-scoped fixture, where a relative URL that worked fine when called directly from a test failed when the page was constructed through the fixture instead.

In both cases the browser is rejecting a URL that Playwright's own client assembled, not one you typed by hand, which is why grepping your own code for the literal string goto( will not find the bug.

How to confirm it: check whether the failure appeared right after a Playwright version bump, and whether your goto() calls go through a baseURL or a custom fixture rather than a bare absolute URL at the call site. If either is true, pin the last known-good Playwright version and confirm the failure disappears before filing this as your own code's mistake.

Cause 3: the message names nothing specific

Verbatim symptom: the same Protocol error (Page.navigate): ... prefix, but the text after it is generic (Target closed, or nothing at all) rather than naming an invalid URL.

This is not this page's cause. It is the target closing at the moment the navigate command was sent, and the three specific Firefox and Juggler reasons that produces are already broken down, with their own verbatim symptoms, on the TargetClosedError page: the automation layer missing from a build, a rejected protocol field from client/browser version drift, or a content process crash mid-navigation. Do not spend time on URL construction if the text does not mention a URL.

Diagnostic checklist

  1. Read everything after Page.navigate): before doing anything else. "Invalid URL" sends you to causes 1 and 2. Anything else sends you to the TargetClosedError page.
  2. Log the literal argument passed to goto() at the call site, not the variable you assume holds it.
  3. Check for a configured baseURL and whether the path you pass is empty, relative, or produces an unexpected join once combined with it.
  4. Note whether the failure is new after a Playwright version bump. Two documented regressions (1.38 to 1.39, and 1.53.2 to 1.54.0) produced this exact string from correct calling code.
  5. Check whether the failing goto() runs inside a custom fixture or a programmatically-created context rather than a plain test body; one regression only reproduced there.
  6. If none of the above resolves it, treat it as TargetClosedError in disguise and work that page's three causes instead.

What invisible_playwright does and does not touch here

This project patches the engine's fingerprint surface, not Playwright's own client-side URL construction or its navigation command dispatch. A Protocol error (Page.navigate) fires from the same client code and the same version-dependent baseURL logic whether the browser underneath is a stock download or a Firefox patched at the C++ level. Nothing about a coherent fingerprint changes what string a goto() call resolves to before it ever reaches the browser.

Conclusion

Protocol error (Page.navigate) is Playwright's own driver reporting that a navigate command was refused, and the reason named after the colon tells you whether that is about the URL or about something else entirely. An invalid or empty URL, often one Playwright's client assembled from a baseURL rather than one you typed, accounts for most reports; a generic or missing reason means the target closed and belongs on the TargetClosedError diagnosis instead.

Short answers to the questions that lead here

What does "Protocol error (Page.navigate)" mean? Playwright's navigation command was sent and the browser (or Playwright's own client-side check) refused it, most often because the URL was empty, relative with no base to resolve against, or otherwise malformed.

Is this a Chromium-only error? No. It is Playwright's internal command name, and reports of the identical string exist against both Chromium and Firefox.

Is this the same as TargetClosedError? No. TargetClosedError means the target was already gone when the call was made. This is a live target refusing one specific command. They can appear together when the refusal itself triggers a close.

I did not pass an empty URL. Why does it still say "invalid URL"? Check your baseURL configuration and any custom fixture that constructs the page. Two documented regressions produced this exact message from correct calling code, because Playwright's own client built the invalid URL internally.

Does upgrading or downgrading Playwright fix it? It can, in both directions, depending on which side of a specific regression you are on. Confirm against the version where your code last worked before assuming a code change is required.

Does invisible_playwright change how goto() resolves URLs? No. URL construction and navigation dispatch are Playwright's own client code, untouched by the engine patching this project does.

Sources

  • Microsoft Playwright issue #27557, a Protocol error (Page.navigate): Invalid url regression between versions 1.38 and 1.39 affecting a custom worker-scoped fixture, on Chromium and Firefox.
  • Microsoft Playwright issue #36753, a Protocol error (Page.navigate): Cannot navigate to invalid URL regression on browser.newContext between versions 1.53.2 and 1.54.0, closed with a linked fix.
  • Microsoft Playwright issue #30336, the same string reported from page.goto("") relying on an unset baseURL.
  • Playwright's own documentation for page.goto(), for what the method throws on and what it returns.

See also: Playwright TargetClosedError: the causes and the fixes, for what this error is not, and Execution context was destroyed, and when it means detection, for the related family of errors produced by a navigation racing your own code rather than being refused outright.


Written while maintaining invisible_playwright, a Firefox patched at the C++ level driven by stock Playwright. Navigation dispatch is Playwright's own client code, so this is a driver-mechanics problem to diagnose, not a fingerprint one.

Documentation

Guides

Comparisons

Integrations

docs/ source folder

Clone this wiki locally