micro/go-micro · error

stream API error (%s): %s

Error message

stream API error (%s): %s

What it means

Returned by Provider.Stream when Anthropic responds with a non-200 status to a streaming request. The error message embeds the HTTP status line and the raw response body, which contains Anthropic's JSON error payload describing the actual failure (invalid API key, bad model name, rate limiting, etc.).

Source

Thrown at ai/anthropic/anthropic.go:268

	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()
		respBody, _ := io.ReadAll(httpResp.Body)
		return nil, fmt.Errorf("stream API error (%s): %s", httpResp.Status, string(respBody))
	}
	return &streamReader{body: httpResp.Body, scanner: bufio.NewScanner(httpResp.Body)}, nil
}

type streamReader struct {
	body    io.ReadCloser
	scanner *bufio.Scanner
	closed  bool
}

func (s *streamReader) Recv() (*ai.Response, error) {
	for s.scanner.Scan() {
		line := strings.TrimSpace(s.scanner.Text())
		if line == "" || strings.HasPrefix(line, ":") || strings.HasPrefix(line, "event:") {
			continue
		}
		if !strings.HasPrefix(line, "data:") {
			continue

View on GitHub (pinned to 24529f1404)

Solutions

  1. Read the body embedded in the error message — it contains Anthropic's error.type and message pinpointing the cause.
  2. Verify ANTHROPIC_API_KEY is valid: curl https://api.anthropic.com/v1/messages with the key and a minimal payload.
  3. Confirm the model ID in the request matches an available Anthropic model and that max_tokens is set (required by the API).
  4. Add retry with backoff for 429/5xx; check response headers retry-after for rate limits.

Example fix

// before
resp, err := provider.Stream(ctx, req)
if err != nil { return err }
// after
resp, err := provider.Stream(ctx, req)
if err != nil {
	var httpErr *ai.HTTPError
	if errors.As(err, &httpErr) && httpErr.StatusCode == 429 {
		time.Sleep(retryAfterBackoff(httpErr))
		resp, err = provider.Stream(ctx, req)
	}
}
Defensive patterns

Strategy: retry

Validate before calling

// before calling: validate key presence and model
func validateOpts(key, model string) error {
	if key == "" { return errors.New("missing ANTHROPIC_API_KEY") }
	if !strings.HasPrefix(model, "claude-") { return errors.New("suspicious model id: "+model) }
	return nil
}

Type guard

func isAnthropicHTTPStatusErr(err error) (status string, body string, ok bool) {
	if err == nil { return };
	re := regexp.MustCompile(`stream API error \((\d{3}[^)]*)\): (.*)`)
	m := re.FindStringSubmatch(err.Error())
	if m == nil { return }
	return m[1], m[2], true
}

Try / catch

resp, err := provider.Stream(ctx, req)
if err != nil {
	if status, body, ok := isAnthropicHTTPStatusErr(err); ok {
		switch {
		case strings.HasPrefix(status, "429"), strings.HasPrefix(status, "5"):
			// retry with backoff
		case strings.HasPrefix(status, "4"):
			// permanent: log body (contains Anthropic error.type), fail fast
		}
	}
}

Prevention

When it happens

Trigger: Any non-200 from POST /v1/messages with stream=true: 401 invalid x-api-key, 400 invalid request (bad model, missing max_tokens), 429 rate limited, 5xx Anthropic outage.

Common situations: Expired or revoked ANTHROPIC_API_KEY, wrong API version header mismatch, requesting a model name that doesn't exist (e.g. typo in claude model ID), hitting org rate limits, or pointing BaseURL at a non-Anthropic-compatible proxy.

Related errors


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