sipeed/picoclaw · error

failed to read response: %w

Error message

failed to read response: %w

What it means

Returned by MimoTTSProvider.Synthesize when io.ReadAll fails while draining resp.Body. The request already succeeded at the transport level; the failure is a mid-body connection reset, the server closing early, context cancellation during the read, or an enormous base64 response exhausting memory.

Source

Thrown at pkg/audio/tts/mimo_tts.go:130

	}

	req, err := http.NewRequestWithContext(ctx, "POST", t.apiBase, bytes.NewReader(jsonData))
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Api-Key", t.apiKey)

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

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

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(body))
	}

	var payload struct {
		Choices []struct {
			Message struct {
				Audio struct {
					Data string `json:"data"`
				} `json:"audio"`
			} `json:"message"`
		} `json:"choices"`
	}

	err = json.Unmarshal(body, &payload)
	if err != nil {

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Retry once — partial reads are usually transient
  2. Shorten the input text to reduce response size
  3. Verify proxy and read-idle timeouts on the network path
  4. Keep the context alive for the entire Synthesize call
Defensive patterns

Strategy: retry

Type guard

func isBodyReadFailure(err error) bool {
    var ne net.Error
    return errors.Is(err, io.ErrUnexpectedEOF) || errors.As(err, &ne)
}

Try / catch

if err != nil && isBodyReadFailure(err) {
    // response broke mid-read: safe to retry — the request body is rebuilt from bytes each attempt
}

Prevention

When it happens

Trigger: Connection dropped between response headers and the final chunk (proxy/idle timeouts); server closes keep-alive early; caller cancels ctx mid-read; multi-MB audio payload for very long text read in one shot.

Common situations: Flaky mobile networks; aggressive corporate proxies; long synthesis inputs producing large base64 bodies.

Related errors


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