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

  1. Log the raw body to see what was actually received.
  2. Check BaseURL points at the official generativelanguage.googleapis.com endpoint (or a proxy that mirrors the exact v1beta schema).
  3. Retry — truncation is usually transient.
  4. 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

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


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/225e5e5fe2fffebb. Report an issue: GitHub.