Skip to content

Error Handling

OmniImage provides structured error types for handling API errors gracefully.

Error Types

Sentinel Errors

import "github.com/plexusone/omniimage"

// Check for specific error types
if errors.Is(err, omniimage.ErrNoProviders) {
    // No providers configured
}

if errors.Is(err, omniimage.ErrUnknownProvider) {
    // Invalid provider name
}

if errors.Is(err, omniimage.ErrNotSupported) {
    // Operation not supported by provider
}

if errors.Is(err, omniimage.ErrRateLimited) {
    // API rate limit exceeded
}

if errors.Is(err, omniimage.ErrContentPolicy) {
    // Content violates provider policy
}

API Errors

var apiErr *omniimage.APIError
if errors.As(err, &apiErr) {
    fmt.Printf("Provider: %s\n", apiErr.Provider)
    fmt.Printf("Status: %d\n", apiErr.StatusCode)
    fmt.Printf("Code: %s\n", apiErr.Code)
    fmt.Printf("Message: %s\n", apiErr.Message)
}

Common Error Scenarios

Invalid API Key

resp, err := client.Generate(ctx, req)
if err != nil {
    var apiErr *omniimage.APIError
    if errors.As(err, &apiErr) && apiErr.StatusCode == 401 {
        log.Fatal("Invalid API key")
    }
}

Rate Limiting

func generateWithRetry(ctx context.Context, client *omniimage.Client, req *provider.GenerateRequest) (*provider.GenerateResponse, error) {
    maxRetries := 3

    for i := 0; i < maxRetries; i++ {
        resp, err := client.Generate(ctx, req)
        if err == nil {
            return resp, nil
        }

        var apiErr *omniimage.APIError
        if errors.As(err, &apiErr) && apiErr.StatusCode == 429 {
            // Exponential backoff
            time.Sleep(time.Duration(1<<i) * time.Second)
            continue
        }

        return nil, err
    }

    return nil, fmt.Errorf("max retries exceeded")
}

Content Policy Violations

resp, err := client.Generate(ctx, req)
if err != nil {
    var apiErr *omniimage.APIError
    if errors.As(err, &apiErr) {
        if apiErr.Code == "content_policy_violation" {
            log.Printf("Prompt violates content policy: %s", apiErr.Message)
            // Modify prompt and retry
            return
        }
    }
}

Unsupported Operations

// Check before calling
if !client.SupportsEdit() {
    return fmt.Errorf("provider does not support editing")
}

resp, err := client.Edit(ctx, editReq)
if err != nil {
    if errors.Is(err, omniimage.ErrNotSupported) {
        // Fallback to different approach
    }
}

Provider-Specific Errors

OpenAI

Status Code Description
400 invalid_request_error Bad request parameters
401 invalid_api_key Invalid API key
403 content_policy_violation Prompt violates policy
429 rate_limit_exceeded Too many requests
500 server_error OpenAI server error

Fal AI

Status Description
400 Invalid request
401 Invalid API key
429 Rate limited
500 Server error

Best Practices

Wrap Errors with Context

resp, err := client.Generate(ctx, req)
if err != nil {
    return fmt.Errorf("generate image for %s: %w", userID, err)
}

Log Errors Appropriately

resp, err := client.Generate(ctx, req)
if err != nil {
    var apiErr *omniimage.APIError
    if errors.As(err, &apiErr) {
        slog.Error("image generation failed",
            "provider", apiErr.Provider,
            "status", apiErr.StatusCode,
            "code", apiErr.Code,
            "message", apiErr.Message,
        )
    } else {
        slog.Error("image generation failed", "error", err)
    }
    return err
}

Graceful Degradation

func generateImage(ctx context.Context, prompt string) (string, error) {
    // Try primary provider
    resp, err := primaryClient.Generate(ctx, &provider.GenerateRequest{
        Model:  omniimage.ModelGPTImage2,
        Prompt: prompt,
    })
    if err == nil {
        return resp.Images[0].URL, nil
    }

    // Log and try fallback
    slog.Warn("primary provider failed, trying fallback", "error", err)

    resp, err = fallbackClient.Generate(ctx, &provider.GenerateRequest{
        Model:  omniimage.ModelFluxPro,
        Prompt: prompt,
    })
    if err != nil {
        return "", fmt.Errorf("all providers failed: %w", err)
    }

    return resp.Images[0].URL, nil
}