{"record":{"id":"4f9bfafde4b8e73e","repo":"micro/go-micro","slug":"gemini-stream-error-s-s","errorCode":null,"errorMessage":"gemini stream error (%s): %s","messagePattern":"gemini stream error \\((.+?)\\): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ai/gemini/gemini.go","lineNumber":249,"sourceCode":"\t\t\t} `json:\"error\"`\n\t\t\tCandidates []struct {\n\t\t\t\tContent struct {\n\t\t\t\t\tParts []struct {\n\t\t\t\t\t\tText string `json:\"text\"`\n\t\t\t\t\t} `json:\"parts\"`\n\t\t\t\t} `json:\"content\"`\n\t\t\t} `json:\"candidates\"`\n\t\t\tUsageMetadata *struct {\n\t\t\t\tPromptTokenCount     int `json:\"promptTokenCount\"`\n\t\t\t\tCandidatesTokenCount int `json:\"candidatesTokenCount\"`\n\t\t\t\tTotalTokenCount      int `json:\"totalTokenCount\"`\n\t\t\t} `json:\"usageMetadata\"`\n\t\t}\n\t\tif err := json.Unmarshal([]byte(data), &chunk); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse stream chunk: %w\", err)\n\t\t}\n\t\tif chunk.Error != nil {\n\t\t\treturn nil, fmt.Errorf(\"gemini stream error (%s): %s\", chunk.Error.Status, chunk.Error.Message)\n\t\t}\n\t\tfor _, candidate := range chunk.Candidates {\n\t\t\tvar parts []string\n\t\t\tfor _, part := range candidate.Content.Parts {\n\t\t\t\tif part.Text != \"\" {\n\t\t\t\t\tparts = append(parts, part.Text)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(parts) > 0 {\n\t\t\t\treturn &ai.Response{Reply: strings.Join(parts, \"\")}, nil\n\t\t\t}\n\t\t}\n\t\tif chunk.UsageMetadata != nil {\n\t\t\treturn &ai.Response{Usage: ai.Usage{\n\t\t\t\tInputTokens:  chunk.UsageMetadata.PromptTokenCount,\n\t\t\t\tOutputTokens: chunk.UsageMetadata.CandidatesTokenCount,\n\t\t\t\tTotalTokens:  chunk.UsageMetadata.TotalTokenCount,\n\t\t\t}}, nil","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/ai/gemini/gemini.go#L231-L267","documentation":"The Gemini stream delivered a chunk whose top-level \"error\" field was set, meaning the API itself reported a mid-stream failure (e.g. quota exceeded, invalid API key, model error). The library surfaces it as 'gemini stream error (<status>): <message>' with the provider's status and message verbatim. The request reached the API and was accepted at transport level, then failed server-side.","triggerScenarios":"Recv on a stream where Gemini emitted {\"error\": {\"status\": ..., \"message\": ...}} — typically RESOURCE_EXHAUSTED, UNAUTHENTICATED (bad x-goog-api-key), INVALID_ARGUMENT, or model unavailability.","commonSituations":"Expired/incorrect GEMINI API key; exhausted free-tier quota or rate limit; invalid model name passed request-stage validation; prompts exceeding context limits; regional availability issues.","solutions":["Parse the status code in the message: RESOURCE_EXHAUSTED → check quota/billing; UNAUTHENTICATED → fix API key; INVALID_ARGUMENT → fix request params.","Verify x-goog-api-key corresponds to a valid, enabled key with Generative Language API access.","If quota-related, enable billing on the Google Cloud project or add client-side rate limiting/backoff.","Retry after the delay suggested in the message for transient capacity errors."],"exampleFix":"// before\nchunk, err := stream.Recv(ctx)\nif err != nil { return err }\n// after\nchunk, err := stream.Recv(ctx)\nif err != nil {\n    var quotaErr *QuotaExceededError\n    if strings.Contains(err.Error(), \"RESOURCE_EXHAUSTED\") && errors.As(err, &quotaErr) {\n        time.Sleep(quotaErr.RetryAfter)\n        chunk, err = stream.Recv(ctx)\n    }\n    if err != nil { return err }\n}","handlingStrategy":"type-guard","validationCode":"if apiKey == \"\" || !strings.HasPrefix(apiKey, \"AI\") {\n    return errors.New(\"GEMINI API key missing or malformed\")\n}\n// also pre-check model name against supported list","typeGuard":"type GeminiStreamError struct{ Status, Message string }\nfunc asGeminiStreamError(err error) (status, msg string, ok bool) {\n    if err == nil { return \"\", \"\", false }\n    const p = \"gemini stream error (\"\n    i := strings.Index(err.Error(), p)\n    if i < 0 { return \"\", \"\", false }\n    rest := err.Error()[i+len(p):]\n    j := strings.Index(rest, \"): \")\n    if j < 0 { return \"\", \"\", false }\n    return rest[:j], rest[j+3:], true\n}","tryCatchPattern":"text, err := stream.Recv(ctx)\nif err != nil {\n    if status, msg, ok := asGeminiStreamError(err); ok {\n        switch status {\n        case \"RESOURCE_EXHAUSTED\":\n            return backoffAndRetry(ctx, req)\n        case \"UNAUTHENTICATED\":\n            return fmt.Errorf(\"check GEMINI API key: %s\", msg)\n        default:\n            return fmt.Errorf(\"gemini %s: %s\", status, msg)\n        }\n    }\n    return err\n}","preventionTips":["Validate the API key and quota before starting streams","Implement client-side rate limiting to avoid RESOURCE_EXHAUSTED","Keep model names current with the Gemini API docs","Route on error status: retry quota errors, hard-fail auth errors"],"tags":["gemini","streaming","api-error","quota","authentication"],"backgroundTag":"gemini-api-error","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}