{"record":{"id":"f4cff17255973b8e","repo":"micro/go-micro","slug":"api-error-s-s-f4cff1","errorCode":null,"errorMessage":"API error (%s): %s","messagePattern":"API error \\((.+?)\\): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ai/openai/openai.go","lineNumber":427,"sourceCode":"\n\tapiURL := strings.TrimRight(p.opts.BaseURL, \"/\") + \"/v1/images/generations\"\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 request: %w\", err)\n\t}\n\n\thttpReq.Header.Set(\"Content-Type\", \"application/json\")\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(\"API request failed: %w\", err)\n\t}\n\tdefer httpResp.Body.Close()\n\n\trespBody, _ := io.ReadAll(httpResp.Body)\n\tif httpResp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"API error (%s): %s\", httpResp.Status, string(respBody))\n\t}\n\n\tvar imgResp struct {\n\t\tData []struct {\n\t\t\tURL     string `json:\"url\"`\n\t\t\tB64JSON string `json:\"b64_json\"`\n\t\t} `json:\"data\"`\n\t}\n\n\tif err := json.Unmarshal(respBody, &imgResp); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse response: %w\", err)\n\t}\n\n\tresponse := &ai.ImageResponse{}\n\tfor _, d := range imgResp.Data {\n\t\tresponse.Images = append(response.Images, ai.Image{\n\t\t\tURL:    d.URL,\n\t\t\tBase64: d.B64JSON,","sourceCodeStart":409,"sourceCodeEnd":445,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/ai/openai/openai.go#L409-L445","documentation":"The image-generation endpoint returned a non-200 HTTP status. The library surfaces the status line and the raw response body so the caller can see the upstream API's error message (auth failure, invalid model, rate limit, content policy, etc.).","triggerScenarios":"httpResp.StatusCode != http.StatusOK after POSTing to /v1/images/generations: 401 invalid API key, 404 wrong BaseURL path, 429 rate limited, 400 invalid size/model/prompt, 5xx upstream outage.","commonSituations":"Expired or wrong API key without image access, using a chat-only endpoint/proxy that lacks /v1/images/generations, requesting a size the model does not support (e.g. dall-e-3 with unsupported dimensions), quota exhaustion.","solutions":["Read the included body text — it contains OpenAI's exact error message","Verify the API key is valid and has image-generation access (401/403)","Confirm BaseURL + /v1/images/generations exists on the target service (404)","On 429, back off and retry; on 400, correct model/size/prompt parameters"],"exampleFix":"// before\np := openai.NewProvider(openai.WithAPIKey(skChatOnly), openai.WithBaseURL(\"https://api.openai.com\"))\n// after\np := openai.NewProvider(openai.WithAPIKey(validKeyWithImageAccess), openai.WithBaseURL(\"https://api.openai.com\"))","handlingStrategy":"type-guard","validationCode":"if apiKey == \"\" {\n    return fmt.Errorf(\"missing API key\")\n}\n// optionally pre-check key validity:\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 invalid or lacks access\")\n}","typeGuard":"type apiStatusError struct{ Status int; Body string }\nfunc asAPIStatusError(err error) (apiStatusError, bool) {\n    msg := err.Error()\n    var status int\n    if _, scanErr := fmt.Sscanf(msg, \"API error (%d\", &status); scanErr == nil {\n        return apiStatusError{Status: status, Body: msg}, true\n    }\n    return apiStatusError{}, false\n}","tryCatchPattern":"resp, err := provider.GenerateImage(ctx, req)\nif e, ok := asAPIStatusError(err); ok {\n    switch {\n    case e.Status == 401 || e.Status == 403:\n        return fmt.Errorf(\"check API key / image access\")\n    case e.Status == 429:\n        // backoff and retry\n    case e.Status >= 500:\n        // retry later\n    default:\n        return fmt.Errorf(\"request rejected: %s\", e.Body)\n    }\n}","preventionTips":["Validate API keys at startup with a cheap /v1/models call","Confirm the target service supports /v1/images/generations","Use documented size/model combos (e.g. dall-e-3 allowed sizes)","Implement 429 backoff and 5xx retry policies"],"tags":["http","api-error","image-generation","openai","status-code"],"backgroundTag":"http-api-error-response","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}