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

  1. Check response.status() before calling body(): if (response.status() < 300 || response.status() >= 400) { const body = await response.body(); }.
  2. Filter redirect responses in response listeners: page.on('response', async response => { if (response.headers()['location']) return; ... }).
  3. 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

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


AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12). Data as JSON: /api/errors/300fc3950959e8b3. Report an issue: GitHub.