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
- Check res.status() first and skip body reads for any 3xx
- 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
- 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
- Always check res.status() for 3xx before body/text/json
- Remember browser Responses for followed redirects represent the final document
- Use page.route to inspect redirect hop bodies when truly needed
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
- unmarshalling response body to JSON: %w
- fetching response body: %w
- getting response body: %w
- getting response body as text: %w
- k6/experimental/browser has been graduated, please use k6/br
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/650059b0e14378f1.
Report an issue: GitHub.