micro/go-micro · error

failed to marshal stream request: %w

Error message

failed to marshal stream request: %w

What it means

The Anthropic streaming provider builds the API request body (model, messages, reasoning options, stream flag) and marshals it to JSON before POSTing to /v1/messages. If json.Marshal fails — essentially only via unsupported values in the request (e.g. invalid map keys, unencodable types introduced by custom options) — the error is wrapped and returned from Stream before any network call.

Source

Thrown at ai/anthropic/anthropic.go:248

		break
	}

	return resp, nil
}

// Stream generates a streaming response from Anthropic's Messages SSE API.
func (p *Provider) Stream(ctx context.Context, req *ai.Request, opts ...ai.GenerateOption) (ai.Stream, error) {
	apiReq := map[string]any{
		"model":      p.opts.Model,
		"max_tokens": anthropicMaxTokens(p.opts),
		"system":     cacheableSystem(req.SystemPrompt, nil, p.opts.NoCache),
		"messages":   threadAnthropicMessages(req),
		"stream":     true,
	}
	applyReasoningOptions(apiReq, p.opts)
	reqBody, err := json.Marshal(apiReq)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal stream request: %w", err)
	}

	apiURL := strings.TrimRight(p.opts.BaseURL, "/") + "/v1/messages"
	httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, apiURL, bytes.NewReader(reqBody))
	if err != nil {
		return nil, fmt.Errorf("failed to create stream request: %w", err)
	}
	httpReq.Header.Set("Content-Type", "application/json")
	httpReq.Header.Set("Accept", "text/event-stream")
	httpReq.Header.Set("x-api-key", p.opts.APIKey)
	httpReq.Header.Set("anthropic-version", "2023-06-01")

	httpResp, err := http.DefaultClient.Do(httpReq)
	if err != nil {
		return nil, fmt.Errorf("stream API request failed: %w", err)
	}
	if httpResp.StatusCode != http.StatusOK {
		defer httpResp.Body.Close()

View on GitHub (pinned to 24529f1404)

Solutions

  1. Inspect the wrapped error to find the unencodable field; ensure option values are JSON-compatible (string-keyed maps, basic types).
  2. Validate custom option payloads marshal on their own with json.Marshal before passing them to the provider.
  3. Upgrade/verify the library version if the failure occurs without custom options (internal bug).

Example fix

// before
opts := []ai.Option{ai.WithMetadata(map[int]string{1: "x"})} // unencodable keys
// after
opts := []ai.Option{ai.WithMetadata(map[string]string{"env": "prod"})}
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := json.Marshal(customOptionsPayload); err != nil {
    return fmt.Errorf("invalid option payload: %w", err)
}

Try / catch

stream, err := provider.Stream(ctx, req)
if err != nil && strings.Contains(err.Error(), "failed to marshal stream request") {
    return fmt.Errorf("request contains non-JSON-encodable option values: %w", err)
}

Prevention

When it happens

Trigger: Any value inside apiReq that encoding/json cannot marshal, such as a map with non-string keys introduced via custom provider options or a malformed custom field; structurally invalid request construction.

Common situations: Passing arbitrary metadata/options with non-string-keyed maps; injecting custom request fields of unsupported types; regressions after customizing provider options.

Related errors


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