{"record":{"id":"8a20c9911845fd4b","repo":"chenhg5/cc-connect","slug":"gemini-stt-empty-response","errorCode":null,"errorMessage":"gemini stt: empty response","messagePattern":"gemini stt: empty response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"core/speech.go","lineNumber":293,"sourceCode":"\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn \"\", fmt.Errorf(\"gemini stt API %d: %s\", resp.StatusCode, string(body))\n\t}\n\n\tvar result struct {\n\t\tCandidates []struct {\n\t\t\tContent struct {\n\t\t\t\tParts []struct {\n\t\t\t\t\tText string `json:\"text\"`\n\t\t\t\t} `json:\"parts\"`\n\t\t\t} `json:\"content\"`\n\t\t} `json:\"candidates\"`\n\t}\n\tif err := json.Unmarshal(body, &result); err != nil {\n\t\treturn \"\", fmt.Errorf(\"gemini stt: parse response: %w\", err)\n\t}\n\tif len(result.Candidates) == 0 || len(result.Candidates[0].Content.Parts) == 0 {\n\t\treturn \"\", fmt.Errorf(\"gemini stt: empty response\")\n\t}\n\n\treturn strings.TrimSpace(result.Candidates[0].Content.Parts[0].Text), nil\n}\n\n// ConvertAudioToMP3 uses ffmpeg to convert audio from unsupported formats to mp3.\n// Returns the mp3 bytes. If ffmpeg is not installed, returns an error.\n// The ctx is honored: cancellation kills the ffmpeg subprocess, matching the\n// behavior of the other Convert* helpers in this file.\nfunc ConvertAudioToMP3(ctx context.Context, audio []byte, srcFormat string) ([]byte, error) {\n\tffmpegPath, err := exec.LookPath(\"ffmpeg\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"ffmpeg not found in PATH: install ffmpeg to enable voice message support\")\n\t}\n\n\tvar cmd *exec.Cmd\n\tif srcFormat == \"amr\" || srcFormat == \"silk\" {\n\t\tcmd = exec.CommandContext(ctx, ffmpegPath,","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/speech.go#L275-L311","documentation":"Thrown by GeminiSTT.Transcribe in core/speech.go when the Gemini response parses as valid JSON but contains no candidates, or the first candidate has no content parts. The API returned 200 with a well-formed body yet no transcription text — commonly a safety-block or empty-generation result.","triggerScenarios":"result.Candidates is empty OR result.Candidates[0].Content.Parts is empty: the prompt was blocked by safety filters, the audio contained no recognizable speech, the model returned a finishReason of SAFETY/RECITATION with no parts, or a maxOutputTokens of 0 consumed everything.","commonSituations":"Voice message is silence/noise; audio content triggers Gemini safety filters; model revision changed default safety behavior; malformed inline audio data that decodes to nothing.","solutions":["Check the audio actually contains speech and is a supported, non-corrupt format (convert with ConvertAudioToMP3).","Log the full response to inspect candidates[0].finishReason and safetyRatings.","Retry with a different Gemini model revision if safety filtering is the cause.","Return a user-friendly 'could not transcribe' message rather than a system error.","Verify the base64 audio data sent in inlineData is complete and correctly encoded."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"info, err := os.Stat(audioPath)\nif err != nil || info.Size() < 1024 { return errors.New(\"audio file too small or missing\") }","typeGuard":null,"tryCatchPattern":"text, err := stt.Transcribe(ctx, audio)\nif err != nil {\n    if strings.Contains(err.Error(), \"empty response\") {\n        return \"\", ErrNoSpeechDetected // show 'could not transcribe' to user\n    }\n    return err\n}","preventionTips":["Pre-check audio contains actual speech before calling the API.","Convert audio to mp3 with ConvertAudioToMP3 to avoid decode failures.","Log finishReason/safetyRatings from the full response to distinguish safety blocks from silence.","Offer users a retry or a different provider when transcription comes back empty."],"tags":["speech-to-text","gemini","empty-response","audio"],"backgroundTag":"empty-api-response","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}