microsoft/playwright · error · Error
${response.status} ${response.statusText}${responseText}
Error message
${response.status} ${response.statusText}${responseText} What it means
Thrown by APIRequestContext.fetch when failOnStatusCode is enabled and the HTTP response status is outside the 2xx/3xx success range (status < 200 or status >= 400). The message carries the status code, status text, and up to the first 1000 chars of the response body so the caller can see the server's error payload.
Solutions
- Set failOnStatusCode: false on the call (or remove it) and inspect response.status()/response.text() manually.
- Fix the request: correct the URL/method/headers/auth so the endpoint returns 2xx.
- Add the required authentication (httpCredentials, Authorization header) before the call.
- If you want non-2xx to be a soft path, branch on response.ok() instead of relying on the throw.
Example fix
// before
const resp = await request.get(url, { failOnStatusCode: true }); // throws on 404
// after
const resp = await request.get(url);
if (!resp.ok()) console.warn(resp.status(), await resp.text()); Defensive patterns
Strategy: validation
Validate before calling
// Check endpoint health before asserting on status const resp = await request.get(url); expect(resp.ok()).toBe(true); // or branch manually
Type guard
// Type guard via the public API surface
function isApiError(e: unknown, code: number) {
return e instanceof Error && e.message.startsWith(String(code) + ' ');
} Try / catch
// Only retry on transient 5xx when failOnStatusCode is off
const resp = await request.get(url);
if (resp.status() >= 500) { /* retry policy */ } Prevention
- Prefer response.ok() branching over failOnStatusCode for resilient tests.
- Keep auth/credentials in the context rather than per-call.
- Validate the URL and base URL at config time.
When it happens
Trigger: Calling request.get/post/put/head/etc. (or APIRequestContext.fetch) with failOnStatusCode: true against an endpoint that returns 4xx (e.g. 404 Not Found, 401 Unauthorized, 403 Forbidden) or 5xx (500, 502, 503). It also fires when failOnStatusCode is set as a default on the APIRequestContext/BrowserContext options.
Common situations: Testing an API that returns error bodies; hitting auth-protected endpoints without credentials; pointing at a wrong base URL returning 404; behind a proxy/gateway returning 502/503; backend returning 500 during a deploy.
Related errors
- Browser does not support socks5 proxy authentication
- Cannot fulfill with redirect status
- Cannot install on
- Creating new API request contexts is not allowed.
- Failed after attempt(s)
AI-assisted analysis of microsoft/playwright@312030cdce (2026-08-12).
Data as JSON: /api/errors/a31c7fb85b7eb7af.
Report an issue: GitHub.
Appendix: source
Thrown at packages/playwright-core/src/server/fetch.ts:259
};
// rejectUnauthorized = undefined is treated as true in Node.js 12.
if (params.ignoreHTTPSErrors || defaults.ignoreHTTPSErrors)
options.rejectUnauthorized = false;
const postData = serializePostData(params, headers);
if (postData)
setHeader(headers, 'content-length', String(postData.byteLength));
const { body, log, response } = await this._sendRequestWithRetries(progress, requestUrl, options, postData, params.maxRetries);
const failOnStatusCode = params.failOnStatusCode !== undefined ? params.failOnStatusCode : !!defaults.failOnStatusCode;
if (failOnStatusCode && (response.status < 200 || response.status >= 400)) {
let responseText = '';
if (body.byteLength) {
let text = body.toString('utf8');
if (text.length > 1000)
text = text.substring(0, 997) + '...';
responseText = `\nResponse text:\n${text}`;
}
throw new Error(`${response.status} ${response.statusText}${responseText}`);
}
const fetchUid = this._storeResponseBody(body);
this.fetchLog.set(fetchUid, log);
return { ...response, fetchUid };
}
private _parseSetCookieHeader(responseUrl: string, setCookie: string[] | undefined): channels.NetworkCookie[] {
if (!setCookie)
return [];
const url = new URL(responseUrl);
// https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4
const defaultPath = '/' + url.pathname.substr(1).split('/').slice(0, -1).join('/');
const cookies: channels.NetworkCookie[] = [];
for (const header of setCookie) {
// Decode cookie value?
const cookie: channels.NetworkCookie | null = parseCookie(header);
if (!cookie)
continue;View on GitHub (pinned to 312030cdce)