{"record":{"id":"8e7b1886c1fc6f73","repo":"chenhg5/cc-connect","slug":"gemini-stt-api-d-s","errorCode":null,"errorMessage":"gemini stt API %d: %s","messagePattern":"gemini stt API (.+?): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/speech.go","lineNumber":277,"sourceCode":"\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"gemini stt: create request: %w\", err)\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\treq.Header.Set(\"x-goog-api-key\", g.APIKey)\n\n\tresp, err := g.Client.Do(req)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"gemini stt: request: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"gemini stt: read response: %w\", err)\n\t}\n\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","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/speech.go#L259-L295","documentation":"Thrown by GeminiSTT.Transcribe in core/speech.go when the Gemini API returns a non-200 HTTP status. The error embeds the status code and the raw response body (Gemini error JSON typically explains invalid API key, bad model, quota exhaustion, or malformed request).","triggerScenarios":"The POST to {BaseURL}/models/{model}:generateContent responds with any status other than 200: 400 invalid request/unsupported audio MIME, 401/403 invalid or missing API key, 404 unknown model name, 429 quota exceeded, 500/503 Gemini outage.","commonSituations":"Missing or revoked GEMINI/Google AI Studio API key; model name typo (e.g. gemini-1.5-flash vs deleted preview version); audio MIME type not supported by the model; free-tier quota exhausted; regional blocking of the API.","solutions":["Read the status code and body in the error: 401/403 -> fix the API key; 404 -> fix the model name; 400 -> check audio format/MIME; 429 -> wait or raise quota.","Verify the Gemini API key is set and valid in config.toml/env.","Confirm the configured model exists for your account/region (Google AI Studio model list).","Convert audio to a supported format (mp3) via ConvertAudioToMP3.","For 429/5xx, retry with exponential backoff."],"exampleFix":"// before\nmodel = \"gemini-pro\" // does not accept audio -> 400\n// after\nmodel = \"gemini-1.5-flash\" // audio-capable model, valid API key","handlingStrategy":"try-catch","validationCode":"if g.APIKey == \"\" { return errors.New(\"gemini: missing API key\") }\nif !strings.Contains(g.Model, \"gemini\") { return fmt.Errorf(\"gemini: suspicious model name %q\", g.Model) }","typeGuard":null,"tryCatchPattern":"text, err := stt.Transcribe(ctx, audio)\nif err != nil {\n    if strings.Contains(err.Error(), \"gemini stt API 429\") {\n        return \"\", ErrRateLimited // back off and retry later\n    }\n    if strings.Contains(err.Error(), \"gemini stt API 40\") {\n        return \"\", ErrConfigInvalid // key/model/audit request problem\n    }\n    return err\n}","preventionTips":["Validate the Gemini API key at startup (cheap models:list call or doctor check).","Keep model names current — preview models get retired.","Send only supported audio MIME types (convert to mp3 first).","Watch quota usage; back off on 429 with exponential delay.","Read the error body: Gemini includes a human-readable reason in JSON."],"tags":["network","http","speech-to-text","gemini","api-error"],"backgroundTag":"http-error-response","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}