sipeed/picoclaw · error
failed to decode response: %w
Error message
failed to decode response: %w
What it means
Returned by MimoTTSProvider.Synthesize when a 200-status body does not match the expected JSON shape (choices[].message.audio.data). json.Unmarshal fails when the body is an HTML error page delivered with HTTP 200 (captive portal/gateway), empty, or when the provider changes its response schema.
Source
Thrown at pkg/audio/tts/mimo_tts.go:149
}
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 {
return nil, fmt.Errorf("failed to decode response: %w", err)
}
if len(payload.Choices) == 0 || payload.Choices[0].Message.Audio.Data == "" {
return nil, fmt.Errorf("invalid TTS response: missing audio data")
}
audioBytes, err := base64.StdEncoding.DecodeString(payload.Choices[0].Message.Audio.Data)
if err != nil {
return nil, fmt.Errorf("failed to decode audio data: %w", err)
}
return io.NopCloser(bytes.NewReader(audioBytes)), nil
}
View on GitHub (pinned to 49183d7e8d)
Solutions
- Log the raw body alongside the unmarshal error to see what actually arrived
- Verify the resolved apiBase ends with /v1/chat/completions for api.xiaomimimo.com
- Whitelist the API host through proxies/captive portals
- Track provider changelogs for schema changes and update the payload struct
Defensive patterns
Strategy: try-catch
Type guard
func isJSONShapeError(err error) bool {
var se *json.SyntaxError
var te *json.UnmarshalTypeError
return errors.As(err, &se) || errors.As(err, &te)
} Try / catch
if err != nil && isJSONShapeError(err) {
// 200 with non-contract JSON: check for captive portals/proxies on the path
// and confirm apiBase still resolves to /v1/chat/completions
} Prevention
- Whitelist api.xiaomimimo.com through proxies and captive portals
- Log the raw body when decode fails to distinguish HTML gateways from schema drift
- Monitor provider changelogs for response schema changes
When it happens
Trigger: A transparent proxy or captive portal returns an HTML block page with status 200; the resolved apiBase drifted away from /v1/chat/completions; the provider shipped a schema change.
Common situations: Guest/portal Wi-Fi; custom api_base normalization mistakes; provider API version bumps.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- API error (status %d): %s
- invalid TTS response: missing audio data
- Failed to save config
- decode process hook %q %s result: %w
- failed to send request: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/868666af258fb4f2.
Report an issue: GitHub.