micro/go-micro · error

failed to parse stream chunk: %w

Error message

failed to parse stream chunk: %w

What it means

Recv received an SSE data payload from the Gemini stream and json.Unmarshal failed to decode it into the chunk struct. This indicates the stream delivered data that does not match the expected Gemini streaming response schema — an unexpected payload shape, truncation, or a non-Gemini endpoint behind BaseURL.

Source

Thrown at ai/gemini/gemini.go:246

				Code    int    `json:"code"`
				Message string `json:"message"`
				Status  string `json:"status"`
			} `json:"error"`
			Candidates []struct {
				Content struct {
					Parts []struct {
						Text string `json:"text"`
					} `json:"parts"`
				} `json:"content"`
			} `json:"candidates"`
			UsageMetadata *struct {
				PromptTokenCount     int `json:"promptTokenCount"`
				CandidatesTokenCount int `json:"candidatesTokenCount"`
				TotalTokenCount      int `json:"totalTokenCount"`
			} `json:"usageMetadata"`
		}
		if err := json.Unmarshal([]byte(data), &chunk); err != nil {
			return nil, fmt.Errorf("failed to parse stream chunk: %w", err)
		}
		if chunk.Error != nil {
			return nil, fmt.Errorf("gemini stream error (%s): %s", chunk.Error.Status, chunk.Error.Message)
		}
		for _, candidate := range chunk.Candidates {
			var parts []string
			for _, part := range candidate.Content.Parts {
				if part.Text != "" {
					parts = append(parts, part.Text)
				}
			}
			if len(parts) > 0 {
				return &ai.Response{Reply: strings.Join(parts, "")}, nil
			}
		}
		if chunk.UsageMetadata != nil {
			return &ai.Response{Usage: ai.Usage{
				InputTokens:  chunk.UsageMetadata.PromptTokenCount,

View on GitHub (pinned to 24529f1404)

Solutions

  1. Log the raw 'data' payload when this error occurs to see what the endpoint actually sent.
  2. Verify BaseURL points to a genuine Gemini v1beta SSE endpoint, not a shim with divergent schema.
  3. Upgrade the library to pick up schema fixes for newer Gemini API responses.
  4. Recover by closing the stream and retrying the request — truncated chunks are often transient.

Example fix

// before
text, err := stream.Recv(ctx)
if err != nil { return err }
// after
text, err := stream.Recv(ctx)
if err != nil {
    if strings.Contains(err.Error(), "failed to parse stream chunk") {
        return fmt.Errorf("bad chunk from endpoint; check BaseURL/schema: %w", err)
    }
    return err
}
Defensive patterns

Strategy: try-catch

Type guard

func isChunkParseErr(err error) bool {
    return err != nil && strings.Contains(err.Error(), "failed to parse stream chunk")
}

Try / catch

text, err := stream.Recv(ctx)
if err != nil {
    if isChunkParseErr(err) {
        log.Printf("malformed chunk; closing stream and retrying request")
        stream.Close()
        return retryRequest(ctx, req)
    }
    return err
}

Prevention

When it happens

Trigger: The SSE 'data:' line's JSON lacked expected fields (candidates/error/usageMetadata shapes changed) or contained invalid/truncated JSON, during a Stream call's Recv loop.

Common situations: Proxy that mangles SSE bodies; pointing BaseURL at a Gemini-compatible gateway with slightly different response schema; Gemini API schema evolution; connection cut mid-JSON.

Understand the failure class

Related errors


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/6d2cce72b6f0d841. Report an issue: GitHub.