ory/hydra · error

Failed to read response: %s

Error message

Failed to read response: %s

What it means

Returned when reading the response body of the admin device-accept call fails. The body is read through io.LimitReader(res.Body, 1<<20) (1 MiB cap); io.ReadAll errors on premature connection close, chunked-encoding corruption, or read timeouts. The handler responds with a 500.

Source

Thrown at cmd/cmd_perform_device_flow.go:224

		http.Error(w, fmt.Sprintf("Failed to create request: %s", err), http.StatusInternalServerError)
		return
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json")

	hc := cfg.HTTPClient
	if hc == nil {
		hc = http.DefaultClient
	}
	res, err := hc.Do(req)
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to accept user code request: %s", err), http.StatusInternalServerError)
		return
	}
	defer res.Body.Close() //nolint:errcheck
	raw, err := io.ReadAll(io.LimitReader(res.Body, 1<<20))
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to read response: %s", err), http.StatusInternalServerError)
		return
	}
	if res.StatusCode != http.StatusOK {
		http.Error(w, fmt.Sprintf("Failed to accept user code request: %s", raw), http.StatusInternalServerError)
		return
	}
	var accepted struct {
		RedirectTo string `json:"redirect_to"`
	}
	if err := json.Unmarshal(raw, &accepted); err != nil || accepted.RedirectTo == "" {
		http.Error(w, "Malformed response from the accept endpoint", http.StatusInternalServerError)
		return
	}

	http.Redirect(w, r, accepted.RedirectTo, http.StatusSeeOther)
}

func (s *deviceSrv) GETdone(w http.ResponseWriter, r *http.Request) {

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Retry the whole accept request once on read failure — the error is transient and the PUT is idempotent for the same challenge.
  2. Check proxy/load-balancer timeout settings between the CLI and Hydra admin and raise read timeouts.
  3. Inspect Hydra admin logs at the same timestamp for a panic or early exit producing a truncated response.

Example fix

// before
raw, err := io.ReadAll(io.LimitReader(res.Body, 1<<20))
if err != nil {
	http.Error(w, fmt.Sprintf("Failed to read response: %s", err), http.StatusInternalServerError)
	return
}
// after
raw, err := io.ReadAll(io.LimitReader(res.Body, 1<<20))
if err != nil {
	logger.Errorf("reading admin response failed: %v", err)
	http.Error(w, "Truncated response from admin endpoint", http.StatusBadGateway)
	return
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check not directly possible; mitigate by bounding the read and checking status early.
if res.StatusCode >= 500 {
	return fmt.Errorf("admin server error %d, body likely truncated/empty", res.StatusCode)
}

Try / catch

raw, err := io.ReadAll(io.LimitReader(res.Body, 1<<20))
if err != nil {
	// retry the whole request once — read errors are usually transient
	if res2, rerr := hc.Do(req.Clone(ctx)); rerr == nil {
		res, raw, err = res2, nil, nil
		raw, err = io.ReadAll(io.LimitReader(res.Body, 1<<20))
	}
	if err != nil {
		http.Error(w, "truncated admin response", http.StatusBadGateway)
		return
	}
}

Prevention

When it happens

Trigger: io.ReadAll(io.LimitReader(res.Body, 1<<20)) at cmd/cmd_perform_device_flow.go:224 returns an error — the Hydra admin connection dropped mid-response, a proxy terminated the chunked body, or a keep-alive/timeout cut the read short.

Common situations: Flaky networks between CLI and admin API; reverse proxies (nginx/traefik) with aggressive timeouts killing long responses; HTTP/1.0 style closes; running behind a load balancer that resets idle connections.

Related errors


AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03). Data as JSON: /api/errors/f9c071e6d5c12d29. Report an issue: GitHub.