microsoft/playwright · error · Error
New URL must have same protocol as overridden URL
Error message
New URL must have same protocol as overridden URL
What it means
Thrown by Route.continue() when the overridden URL has a different protocol than the original request URL. The method constructs new URL objects for both and compares .protocol. Changing protocols (e.g., http to https or vice versa) is not permitted because it can break CORS, mixed-content policies, and the browser's security model. Note: changing the hostname or path is allowed.
Source
Thrown at packages/playwright-core/src/server/network.ts:442
const requestUrl = new URL(this._request.url());
if (!requestUrl.protocol.startsWith('http'))
return;
if (requestUrl.origin === origin.trim())
return;
const corsHeader = headers.find(({ name }) => name === 'access-control-allow-origin');
if (corsHeader)
return;
headers.push({ name: 'access-control-allow-origin', value: origin });
headers.push({ name: 'access-control-allow-credentials', value: 'true' });
headers.push({ name: 'vary', value: 'Origin' });
}
async continue(overrides: channels.RouteContinueParams) {
if (overrides.url) {
const newUrl = new URL(overrides.url);
const oldUrl = new URL(this._request.url());
if (oldUrl.protocol !== newUrl.protocol)
throw new Error('New URL must have same protocol as overridden URL');
}
if (overrides.headers) {
// Filter out forbidden headers from overrides - they cannot be overridden
// and will be passed as-is from the original request
overrides.headers = applyHeadersOverrides(this._request._headers, overrides.headers);
}
overrides = this._request._applyOverrides(overrides);
const nextHandler = this._futureHandlers.shift();
if (nextHandler) {
this._currentHandler = nextHandler;
nextHandler(this, this._request);
return;
}
if (!overrides.isFallback)
this._request._context.emit(BrowserContext.Events.RequestContinued, this._request);
this._startHandling();View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Match the protocol of the original request URL when overriding: use the same http:// or https:// scheme.
- Use route.fulfill() with a redirect response (status 301/302 + Location header) instead of route.continue() if a protocol change is needed.
- Fix URL construction to preserve the protocol: new URL(path, originalUrl).toString().
Example fix
// before
await route.continue({ url: 'https://api.example.com/data' }); // original was http://
// after — same protocol
await route.continue({ url: 'http://api.example.com/data' });
// or — fulfill with redirect
await route.fulfill({
status: 301,
headers: { location: 'https://api.example.com/data' }
}); Defensive patterns
Strategy: validation
Validate before calling
function validateOverrideUrl(originalUrl, overrideUrl) {
const oldProto = new URL(originalUrl).protocol;
const newProto = new URL(overrideUrl).protocol;
if (oldProto !== newProto)
throw new Error(`Protocol mismatch: ${oldProto} -> ${newProto}. Use route.fulfill with redirect.`);
} Try / catch
try {
await route.continue({ url: newUrl });
} catch (e) {
if (e.message === 'New URL must have same protocol as overridden URL') {
// Fulfill with redirect instead
await route.fulfill({ status: 302, headers: { location: newUrl } });
} else throw e;
} Prevention
- Match the protocol scheme when overriding URLs in route.continue().
- Use route.fulfill() with a redirect status for protocol changes.
- Construct override URLs from the original URL to preserve the scheme.
When it happens
Trigger: Calling route.continue({ url: newUrl }) in a page.route() handler where newUrl's protocol differs from the intercepted request's protocol. For example, intercepting an http:// request and continuing to an https:// URL, or vice versa. This commonly occurs when normalizing URLs or redirecting from insecure to secure endpoints.
Common situations: Test mock redirects http requests to https endpoints for consistency. Proxying to a different protocol server. Stripping or adding TLS via route override. URL construction bug that drops or changes the protocol scheme.
Related errors
- Response body is unavailable
- Cannot fulfill with redirect status: ${response.status}
- Timeout ${options.timeout}ms exceeded
- ${path}: expected channel ${names.toString()}
- Malformed endpoint. Did you use BrowserType.launchServer met
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/fbbcd17f3ae2e583.
Report an issue: GitHub.