micro/go-micro · error

API error (%s): %s

Error message

API error (%s): %s

What it means

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.).

Source

Thrown at ai/openai/openai.go:427

	apiURL := strings.TrimRight(p.opts.BaseURL, "/") + "/v1/images/generations"
	httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, apiURL, bytes.NewReader(reqBody))
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	httpReq.Header.Set("Content-Type", "application/json")
	httpReq.Header.Set("Authorization", "Bearer "+p.opts.APIKey)

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

	respBody, _ := io.ReadAll(httpResp.Body)
	if httpResp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("API error (%s): %s", httpResp.Status, string(respBody))
	}

	var imgResp struct {
		Data []struct {
			URL     string `json:"url"`
			B64JSON string `json:"b64_json"`
		} `json:"data"`
	}

	if err := json.Unmarshal(respBody, &imgResp); err != nil {
		return nil, fmt.Errorf("failed to parse response: %w", err)
	}

	response := &ai.ImageResponse{}
	for _, d := range imgResp.Data {
		response.Images = append(response.Images, ai.Image{
			URL:    d.URL,
			Base64: d.B64JSON,

View on GitHub (pinned to 24529f1404)

Solutions

  1. Read the included body text — it contains OpenAI's exact error message
  2. Verify the API key is valid and has image-generation access (401/403)
  3. Confirm BaseURL + /v1/images/generations exists on the target service (404)
  4. On 429, back off and retry; on 400, correct model/size/prompt parameters

Example fix

// before
p := openai.NewProvider(openai.WithAPIKey(skChatOnly), openai.WithBaseURL("https://api.openai.com"))
// after
p := openai.NewProvider(openai.WithAPIKey(validKeyWithImageAccess), openai.WithBaseURL("https://api.openai.com"))
Defensive patterns

Strategy: type-guard

Validate before calling

if apiKey == "" {
    return fmt.Errorf("missing API key")
}
// optionally pre-check key validity:
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 invalid or lacks access")
}

Type guard

type apiStatusError struct{ Status int; Body string }
func asAPIStatusError(err error) (apiStatusError, bool) {
    msg := err.Error()
    var status int
    if _, scanErr := fmt.Sscanf(msg, "API error (%d", &status); scanErr == nil {
        return apiStatusError{Status: status, Body: msg}, true
    }
    return apiStatusError{}, false
}

Try / catch

resp, err := provider.GenerateImage(ctx, req)
if e, ok := asAPIStatusError(err); ok {
    switch {
    case e.Status == 401 || e.Status == 403:
        return fmt.Errorf("check API key / image access")
    case e.Status == 429:
        // backoff and retry
    case e.Status >= 500:
        // retry later
    default:
        return fmt.Errorf("request rejected: %s", e.Body)
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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