chenhg5/cc-connect · error
gemini stt: parse response: %w
Error message
gemini stt: parse response: %w
What it means
Thrown by GeminiSTT.Transcribe in core/speech.go when the 200-OK body from Gemini cannot be unmarshaled into the expected {candidates:[{content:{parts:[{text}]}}]} structure. The underlying json.Unmarshal error is wrapped with 'gemini stt: parse response:'. Means the server answered successfully but with an unexpected body format.
Source
Thrown at core/speech.go:290
if err != nil {
return "", fmt.Errorf("gemini stt: read response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("gemini stt API %d: %s", resp.StatusCode, string(body))
}
var result struct {
Candidates []struct {
Content struct {
Parts []struct {
Text string `json:"text"`
} `json:"parts"`
} `json:"content"`
} `json:"candidates"`
}
if err := json.Unmarshal(body, &result); err != nil {
return "", fmt.Errorf("gemini stt: parse response: %w", err)
}
if len(result.Candidates) == 0 || len(result.Candidates[0].Content.Parts) == 0 {
return "", fmt.Errorf("gemini stt: empty response")
}
return strings.TrimSpace(result.Candidates[0].Content.Parts[0].Text), nil
}
// ConvertAudioToMP3 uses ffmpeg to convert audio from unsupported formats to mp3.
// Returns the mp3 bytes. If ffmpeg is not installed, returns an error.
// The ctx is honored: cancellation kills the ffmpeg subprocess, matching the
// behavior of the other Convert* helpers in this file.
func ConvertAudioToMP3(ctx context.Context, audio []byte, srcFormat string) ([]byte, error) {
ffmpegPath, err := exec.LookPath("ffmpeg")
if err != nil {
return nil, fmt.Errorf("ffmpeg not found in PATH: install ffmpeg to enable voice message support")
}
View on GitHub (pinned to 4000b2338a)
Solutions
- Log the raw body to see what was actually received.
- Check BaseURL points at the official generativelanguage.googleapis.com endpoint (or a proxy that mirrors the exact v1beta schema).
- Retry — truncation is usually transient.
- Update the parsing struct in core/speech.go if the Gemini schema changed.
Defensive patterns
Strategy: try-catch
Try / catch
text, err := stt.Transcribe(ctx, audio)
if err != nil {
if strings.Contains(err.Error(), "parse response") {
slog.Warn("gemini stt: unexpected 200 body", "err", err)
return "", ErrUnexpectedResponse
}
return err
} Prevention
- Point BaseURL at the official v1beta endpoint or a schema-faithful proxy.
- Log raw bodies on parse failure for diagnosis.
- Retry once on truncation-style failures.
- Track Gemini API release notes for schema changes and update the struct.
When it happens
Trigger: json.Unmarshal fails on the 200 body: response truncated mid-JSON, a proxy replaced the body with HTML, or the API version at BaseURL returns a different generateContent schema than the parsing struct expects.
Common situations: BaseURL pointing at a non-standard Gemini-compatible proxy with a different response shape; intermittent network truncation; api version mismatch (e.g. v1 vs v1beta differences after Google changes).
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- parse response: %w
- gemini stt: marshal request: %w
- parse JSON from %s: %w
- parse JSON from %s: %w
- gemini stt: create request: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/225e5e5fe2fffebb.
Report an issue: GitHub.