googleapis/mcp-toolbox · error

error decoding stream message: %w

Error message

error decoding stream message: %w

What it means

While iterating the JSON array with decoder.More(), each element is decoded into a StreamMessage struct. This error wraps any decoding failure of an individual stream element that is not io.EOF, meaning an element in the array does not match the expected StreamMessage shape (or the stream ended mid-element).

Source

Thrown at internal/tools/looker/lookerconversationalanalytics/lookerconversationalanalytics.go:467

	var messages []map[string]any
	decoder := json.NewDecoder(resp.Body)

	// The response is a JSON array, so we read the opening bracket.
	if _, err := decoder.Token(); err != nil {
		if err == io.EOF {
			return nil, nil // Empty response is valid
		}
		return nil, fmt.Errorf("error reading start of json array: %w", err)
	}

	for decoder.More() {
		var msg StreamMessage
		if err := decoder.Decode(&msg); err != nil {
			if err == io.EOF {
				break
			}
			return nil, fmt.Errorf("error decoding stream message: %w", err)
		}

		var newMessage map[string]any
		if msg.SystemMessage != nil {
			if msg.SystemMessage.Text != nil {
				newMessage = handleTextResponse(ctx, msg.SystemMessage.Text)
			} else if msg.SystemMessage.Schema != nil {
				newMessage = handleSchemaResponse(ctx, msg.SystemMessage.Schema)
			} else if msg.SystemMessage.Data != nil {
				newMessage = handleDataResponse(ctx, msg.SystemMessage.Data)
			} else if msg.SystemMessage.Analysis != nil {
				newMessage = handleAnalysisResponse(ctx, msg.SystemMessage.Analysis)
			} else if msg.SystemMessage.Error != nil {
				newMessage = handleError(ctx, msg.SystemMessage.Error)
			}
			messages = appendMessage(messages, newMessage)
		}
	}

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Check the wrapped error for the exact JSON field/type mismatch and update the StreamMessage struct (or the library) to match the current API response shape.
  2. Pin/verify the API version being used and check for Conversational Analytics API changelog changes.
  3. Retry the call to rule out a truncated stream from a transient network cut.
  4. Capture the full raw stream with curl for a successful run and compare against the failing payload.

Example fix

// before: struct missing a newly added event field
type StreamMessage struct {
    SystemMessage *SystemMessage `json:"systemMessage"`
}
// after: tolerate unknown/added fields without breaking decode
type StreamMessage struct {
    SystemMessage *SystemMessage `json:"systemMessage"`
    Extra         map[string]any `json:"-"` // inspect payloads during debug
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Go: sanity-check one stream element against the expected shape before bulk decoding
func looksLikeStreamElement(el map[string]any) bool {
    _, ok := el["systemMessage"]
    return ok
}

Type guard

// Go: narrow via a tolerant probe decode
type StreamMessage struct {
    SystemMessage *SystemMessage `json:"systemMessage"`
}
func asStreamMessage(raw json.RawMessage) (*StreamMessage, error) {
    var msg StreamMessage
    dec := json.NewDecoder(bytes.NewReader(raw))
    dec.DisallowUnknownFields = false // tolerate new API fields
    if err := dec.Decode(&msg); err != nil {
        return nil, fmt.Errorf("unexpected stream element: %w", err)
    }
    return &msg, nil
}

Try / catch

result, err := invokeTool(ctx, req)
if err != nil && strings.Contains(err.Error(), "error decoding stream message") {
    log.Printf("stream element shape mismatch, likely API drift: %v", err)
    // fall back to raw passthrough or retry against pinned API version
    return rawFallback(ctx, req)
}

Prevention

When it happens

Trigger: The API emits a stream element with unexpected/extra structure that fails strict decoding into StreamMessage, or the connection is cut mid-element so a partial JSON object is decoded.

Common situations: API version drift introducing new or differently-shaped stream events; corrupted stream due to network interruption; intermediary mangling chunked transfer encoding; the server emitting an error object inside the stream.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/86b6f1c5e52a6af7. Report an issue: GitHub.