{"record":{"id":"57768d82d8e6d844","repo":"micro/go-micro","slug":"stream-api-error-s-s-57768d","errorCode":null,"errorMessage":"stream API error (%s): %s","messagePattern":"stream API error \\((.+?)\\): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ai/openai/openai.go","lineNumber":229,"sourceCode":"\t\treturn nil, fmt.Errorf(\"failed to marshal stream request: %w\", err)\n\t}\n\tapiURL := strings.TrimRight(p.opts.BaseURL, \"/\") + \"/v1/chat/completions\"\n\thttpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, apiURL, bytes.NewReader(reqBody))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create stream request: %w\", err)\n\t}\n\thttpReq.Header.Set(\"Content-Type\", \"application/json\")\n\thttpReq.Header.Set(\"Accept\", \"text/event-stream\")\n\thttpReq.Header.Set(\"Authorization\", \"Bearer \"+p.opts.APIKey)\n\n\thttpResp, err := http.DefaultClient.Do(httpReq)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"stream API request failed: %w\", err)\n\t}\n\tif httpResp.StatusCode != http.StatusOK {\n\t\tdefer httpResp.Body.Close()\n\t\trespBody, _ := io.ReadAll(httpResp.Body)\n\t\treturn nil, fmt.Errorf(\"stream API error (%s): %s\", httpResp.Status, string(respBody))\n\t}\n\treturn &openAIStream{body: httpResp.Body, scanner: bufio.NewScanner(httpResp.Body)}, nil\n}\n\ntype openAIStream struct {\n\tbody    io.ReadCloser\n\tscanner *bufio.Scanner\n\tclosed  bool\n}\n\nfunc (s *openAIStream) Recv() (*ai.Response, error) {\n\tfor s.scanner.Scan() {\n\t\tline := strings.TrimSpace(s.scanner.Text())\n\t\tif line == \"\" || strings.HasPrefix(line, \":\") {\n\t\t\tcontinue\n\t\t}\n\t\tif !strings.HasPrefix(line, \"data:\") {\n\t\t\tcontinue","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/ai/openai/openai.go#L211-L247","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\np, _ := NewProvider(WithAPIKey(\"\")) // 401 Unauthorized\n// after\np, _ := NewProvider(WithAPIKey(os.Getenv(\"OPENAI_API_KEY\")))","handlingStrategy":"try-catch","validationCode":"if apiKey == \"\" {\n    return errors.New(\"OPENAI_API_KEY not set\")\n}\n// optionally: preflight a cheap models list call to validate the key\nreq, _ := http.NewRequest(\"GET\", baseURL+\"/v1/models\", nil)\nreq.Header.Set(\"Authorization\", \"Bearer \"+apiKey)\nresp, err := http.DefaultClient.Do(req)\nif err != nil || resp.StatusCode != 200 {\n    return fmt.Errorf(\"API key/endpoint validation failed (status %d)\", resp.StatusCode)\n}","typeGuard":null,"tryCatchPattern":"_, err := provider.Stream(ctx, req)\nif err != nil {\n    msg := err.Error()\n    switch {\n    case strings.Contains(msg, \"401\"):\n        // fix credentials\n    case strings.Contains(msg, \"429\"):\n        // backoff and retry respecting Retry-After\n    case strings.Contains(msg, \"400\"):\n        // fix model name / unsupported params\n    default:\n        // 5xx: retry with backoff\n    }\n    return err\n}","preventionTips":["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"],"tags":["http","openai","api-error","streaming","authentication"],"backgroundTag":"http-non-200-response","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}