grafana/k6 · warning

response body is unavailable for redirect responses

Error message

response body is unavailable for redirect responses

What it means

Response.Body() deliberately refuses to return bodies for HTTP 3xx responses because the browser follows redirects internally and CDP reports redirect responses with an empty body. This is a designed, deterministic guard evaluated before any fetching: if r.status is 300-399, the call fails immediately with this message.

Source

Thrown at internal/js/modules/k6/browser/common/http.go:663

	headers := make(map[string]string)
	r.extraHeadersMu.RLock()
	if len(r.extraHeaders) != 0 {
		for name, values := range r.extraHeaders {
			headers[strings.ToLower(name)] = strings.Join(values, "\n")
		}
	} else {
		for name, values := range r.headers {
			headers[strings.ToLower(name)] = strings.Join(values, "\n")
		}
	}
	r.extraHeadersMu.RUnlock()
	return headers
}

// Body returns the response body as a bytes buffer.
func (r *Response) Body() ([]byte, error) {
	if r.status >= 300 && r.status <= 399 {
		return nil, fmt.Errorf("response body is unavailable for redirect responses")
	}
	if err := r.fetchBody(); err != nil {
		return nil, fmt.Errorf("getting response body: %w", err)
	}

	r.bodyMu.RLock()
	defer r.bodyMu.RUnlock()

	return r.body, nil
}

// bodySize returns the size in bytes of the response body.
func (r *Response) bodySize() int64 {
	// Skip redirect responses
	if r.status >= 300 && r.status <= 399 {
		return 0
	}

View on GitHub (pinned to 93accf6570)

Solutions

  1. Check res.status() first and skip body reads for any 3xx
  2. Use the final response after the browser followed redirects (e.g. the response of the last navigation), or locate the final response via the request's redirect chain
  3. If you must inspect redirect hop bodies, intercept them with page.route() and inspect/fulfill manually

Example fix

// before
const res = await page.goto('http://example.com'); // 301
const text = await res.text(); // throws

// after
const res = await page.goto('http://example.com');
const text = (res.status() >= 300 && res.status() <= 399) ? '' : await res.text();
Defensive patterns

Strategy: validation

Validate before calling

function isRedirect(res) {
  const s = res.status();
  return s >= 300 && s <= 399;
}
const text = isRedirect(res) ? null : await res.text();

Prevention

When it happens

Trigger: Calling res.body(), res.text() or res.json() on a Response whose status is in 300-399, typically the first hop of a redirect chain (302 to login, 301 http-to-https, 304 negotiation responses).

Common situations: Asserting on a response object that is actually a redirect hop rather than the final document; endpoints that 302 to auth pages; caching flows returning 304; following redirects without realizing the Response object represents the redirect.

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/650059b0e14378f1. Report an issue: GitHub.