sipeed/picoclaw · error

read response: %w

Error message

read response: %w

What it means

The request succeeded (200) but reading the full response body failed mid-stream while io.ReadAll drained it. The connection dropped after headers arrived, and the transport-level cause is wrapped.

Source

Thrown at cmd/picoclaw/internal/model/online.go:57

	req.Header.Set("Authorization", "Bearer "+apiKey)

	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("request failed: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, readErr := io.ReadAll(io.LimitReader(resp.Body, 512))
		if readErr != nil {
			return nil, fmt.Errorf("read error response: %w", readErr)
		}
		return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, strings.TrimSpace(string(body)))
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("read response: %w", err)
	}

	// {"data": [...]} envelope. Distinguish "envelope shape with empty list"
	// from "object without a data key" via Data being non-nil after unmarshal:
	// json.Unmarshal sets Data to []modelEntry{} for `{"data":[]}` but leaves
	// it as nil when "data" is absent or null.
	var envelope modelsAPIResponse
	if err := json.Unmarshal(body, &envelope); err == nil && envelope.Data != nil {
		return envelope.Data, nil
	}

	// Bare-array shape, including `[]`.
	var arr []modelEntry
	if err := json.Unmarshal(body, &arr); err == nil {
		return arr, nil
	}

	preview := body

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Retry — most mid-body drops are transient.
  2. If reproducible, fetch the URL with curl and observe where the body truncates.
  3. For huge catalogs, run from a nearer network or use a provider endpoint with pagination/filtering.
Defensive patterns

Strategy: retry

Try / catch

body, err := io.ReadAll(resp.Body)
if err != nil {
    var nerr net.Error
    if errors.As(err, &nerr) && nerr.Timeout() {
        return retryWithBackoff() // body read exceeded client timeout
    }
    return fmt.Errorf("read response: %w", err)
}

Prevention

When it happens

Trigger: The server or a proxy closes the connection partway through the /models JSON body — RST mid-body, proxy idle cutoff, or the 15s client timeout expiring during a large body read at online.go:57.

Common situations: Very large model catalogs over slow links, flaky mobile/VPN networks, or intermediaries that truncate long responses.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/6e0fc54292327e12. Report an issue: GitHub.