micro/go-micro · error
stream API error (%s): %s
Error message
stream API error (%s): %s
What it means
Thrown in the OpenAI provider's Stream when the chat-completions endpoint responds with a non-200 HTTP status. The provider closes the body, reads it, and includes both the HTTP status (e.g. '401 Unauthorized') and the raw response body in the error so the API's JSON error message is directly visible.
Source
Thrown at ai/openai/openai.go:229
return nil, fmt.Errorf("failed to marshal stream request: %w", err)
}
apiURL := strings.TrimRight(p.opts.BaseURL, "/") + "/v1/chat/completions"
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("Authorization", "Bearer "+p.opts.APIKey)
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 &openAIStream{body: httpResp.Body, scanner: bufio.NewScanner(httpResp.Body)}, nil
}
type openAIStream struct {
body io.ReadCloser
scanner *bufio.Scanner
closed bool
}
func (s *openAIStream) Recv() (*ai.Response, error) {
for s.scanner.Scan() {
line := strings.TrimSpace(s.scanner.Text())
if line == "" || strings.HasPrefix(line, ":") {
continue
}
if !strings.HasPrefix(line, "data:") {
continueView on GitHub (pinned to 24529f1404)
Solutions
- Read status+body in the error: fix credentials if 401, wait/backoff if 429
- Verify the API key is set and valid (echo $OPENAI_API_KEY, check dashboard)
- Correct the model name / remove unsupported parameters (e.g. invalid Effort) if 400
- Check status.openai.com for outages if 5xx, and add retry with backoff
Example fix
// before
p, _ := NewProvider(WithAPIKey("")) // 401 Unauthorized
// after
p, _ := NewProvider(WithAPIKey(os.Getenv("OPENAI_API_KEY"))) Defensive patterns
Strategy: try-catch
Validate before calling
if apiKey == "" {
return errors.New("OPENAI_API_KEY not set")
}
// optionally: preflight a cheap models list call to validate the key
req, _ := http.NewRequest("GET", baseURL+"/v1/models", nil)
req.Header.Set("Authorization", "Bearer "+apiKey)
resp, err := http.DefaultClient.Do(req)
if err != nil || resp.StatusCode != 200 {
return fmt.Errorf("API key/endpoint validation failed (status %d)", resp.StatusCode)
} Try / catch
_, err := provider.Stream(ctx, req)
if err != nil {
msg := err.Error()
switch {
case strings.Contains(msg, "401"):
// fix credentials
case strings.Contains(msg, "429"):
// backoff and retry respecting Retry-After
case strings.Contains(msg, "400"):
// fix model name / unsupported params
default:
// 5xx: retry with backoff
}
return err
} Prevention
- Load and verify the API key before calling Stream
- Preflight with GET /v1/models to catch auth problems early
- Implement backoff for 429/5xx responses
- Keep model names and parameters (e.g. reasoning_effort) valid for the account tier
When it happens
Trigger: Any Stream() call where httpResp.StatusCode != http.StatusOK: 401 invalid API key, 429 rate limit / quota exceeded, 400 bad request (unknown model or parameter like a bad reasoning_effort), 500/503 OpenAI-side outage.
Common situations: Expired or revoked OPENAI_API_KEY; exceeded quota or hit rate limits; requesting a model the account/key can't access (e.g. o1 models needing verified org); passing Effort values the API rejects; regional outages.
Related errors
- stream API error (%s): %s
- gemini stream error (%s): %s
- failed to create stream request: %w
- stream API request failed: %w
- API error (%s): %s
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/57768d82d8e6d844.
Report an issue: GitHub.