microsoft/playwright · error · Error
Response body is unavailable for redirect responses
Error message
Response body is unavailable for redirect responses
What it means
Thrown by Response.internalBody() (which backs response.body() and response.text()) when the response status code is in the 300-399 range, indicating a redirect. Redirect responses have no body by HTTP specification; the browser does not download content for 3xx responses. The check fires inside the _contentPromise lazy initializer after the response is finished.
Source
Thrown at packages/playwright-core/src/server/network.ts:651
}
async internalSecurityDetails(): Promise<SecurityDetails|null> {
return await this._securityDetailsPromise || null;
}
async internalServerAddr(): Promise<RemoteAddr | null> {
return await this._serverAddrPromise || null;
}
async internalRawResponseHeaders(): Promise<HeadersArray> {
return await this._rawResponseHeadersPromise;
}
internalBody(): Promise<Buffer> {
if (!this._contentPromise) {
this._contentPromise = this._finishedPromise.then(async () => {
if (this._status >= 300 && this._status <= 399)
throw new Error('Response body is unavailable for redirect responses');
if (this._request._responseBodyOverride) {
const { body, isBase64 } = this._request._responseBodyOverride;
return Buffer.from(body, isBase64 ? 'base64' : 'utf-8');
}
try {
return await this._getResponseBodyCallback();
} catch (e) {
if (isProtocolError(e) && e.type === 'error')
rewriteErrorMessage(e, e.message + '\nResponse body is not available for a response that was navigated away from. Read response.body() before triggering any navigation.');
throw e;
}
});
}
return this._contentPromise;
}
request(): Request {
return this._request;View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Check response.status() before calling body(): if (response.status() < 300 || response.status() >= 400) { const body = await response.body(); }.
- Filter redirect responses in response listeners: page.on('response', async response => { if (response.headers()['location']) return; ... }).
- Use response.url() and response.status() for redirect inspection instead of body().
Example fix
// before
page.on('response', async response => {
const body = await response.body(); // throws [339] on redirects
log(response.url(), body);
});
// after
page.on('response', async response => {
if (response.status() >= 300 && response.status() <= 399) return;
const body = await response.body();
log(response.url(), body);
}); Defensive patterns
Strategy: validation
Validate before calling
async function safeBody(response) {
const status = response.status();
if (status >= 300 && status <= 399)
return null; // redirect, no body
return response.body();
} Type guard
function hasBody(response: import('@playwright/test').Response): boolean {
const status = response.status();
return status < 300 || status > 399;
} Try / catch
try {
return await response.body();
} catch (e) {
if (e.message === 'Response body is unavailable for redirect responses')
return null;
throw e;
} Prevention
- Check response.status() before calling body() or text().
- Filter redirect responses in page.on('response') listeners.
- Use response.headers()['location'] to detect redirects without reading the body.
When it happens
Trigger: Calling response.body() or response.text() on a Response object whose status code is 301, 302, 303, 307, or 308. This is common when intercepting all responses via page.on('response') and attempting to read the body of every response, including redirects. Also occurs when explicitly following redirects and inspecting intermediate responses.
Common situations: Response listener tries to log or assert on all response bodies without filtering redirects. Test captures a redirect response and calls body() for assertion. page.route() handler inspects the body of a request that received a redirect response. Following redirects but storing references to intermediate redirect Response objects.
Related errors
- Response body is unavailable
- Cannot fulfill with redirect status: ${response.status}
- Timeout ${options.timeout}ms exceeded
- Malformed endpoint. Did you use BrowserType.launchServer met
- Timeout ${params.timeout}ms exceeded
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/300fc3950959e8b3.
Report an issue: GitHub.