Provider Errors
This guide covers common errors specific to different AI providers and how to resolve them.
OpenAI Provider Errors
Error: "Insufficient Quota"
Symptoms:
Error: You exceeded your current quota, please check your plan and billing details
Status Code: 429
Cause: You've exceeded your OpenAI usage quota or haven't set up billing.
Solution:
package main
import (
"context"
"errors"
"fmt"
"log"
"os"
"github.com/digitallysavvy/go-ai/pkg/ai"
providererrors "github.com/digitallysavvy/go-ai/pkg/provider/errors"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
)
func generateWithQuotaFallback(ctx context.Context, prompt string) (string, error) {
provider := openai.New(openai.Config{
APIKey: os.Getenv("OPENAI_API_KEY"),
})
// Try primary model
model, _ := provider.LanguageModel("gpt-4")
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: prompt,
})
if err != nil {
var providerErr *providererrors.ProviderError
if errors.As(err, &providerErr) && providerErr.StatusCode == 429 {
log.Println("Quota exceeded, trying alternative provider or model...")
// Option 1: Use a cheaper model
model, _ = provider.LanguageModel("gpt-4o-mini")
result, err = ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: prompt,
})
if err != nil {
return "", fmt.Errorf("fallback failed: %w", err)
}
return result.Text, nil
}
return "", err
}
return result.Text, nil
}
func main() {
ctx := context.Background()
text, err := generateWithQuotaFallback(ctx, "Explain quantum computing")
if err != nil {
log.Fatalf("Failed: %v", err)
}
fmt.Println(text)
}
Prevention:
- Monitor your OpenAI usage dashboard
- Set up billing alerts
- Implement usage tracking in your application
- Use cheaper models for non-critical tasks
Error: "Model Permission Denied"
Symptoms:
Error: The model 'gpt-4' does not exist or you do not have access to it
Status Code: 404
Cause: Trying to access a model not available in your OpenAI account tier.
Solution:
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/digitallysavvy/go-ai/pkg/ai"
goprovider "github.com/digitallysavvy/go-ai/pkg/provider"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
)
func getAvailableModel(provider *openai.Provider, preferredModels []string) (goprovider.LanguageModel, error) {
ctx := context.Background()
maxTokens := 5
// Try models in order of preference
for _, modelName := range preferredModels {
model, err := provider.LanguageModel(modelName)
if err != nil {
log.Printf("Model %s not available: %v", modelName, err)
continue
}
// Test if model is actually accessible with a cheap request
_, err = ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: "Hi",
MaxTokens: &maxTokens,
})
if err == nil {
log.Printf("Using model: %s", modelName)
return model, nil
}
log.Printf("Model %s access denied: %v", modelName, err)
}
return nil, fmt.Errorf("no available models found")
}
func main() {
provider := openai.New(openai.Config{
APIKey: os.Getenv("OPENAI_API_KEY"),
})
// List models in order of preference
preferredModels := []string{
"gpt-4",
"gpt-4-turbo",
"gpt-4o",
"gpt-3.5-turbo",
}
model, err := getAvailableModel(provider, preferredModels)
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: "Explain quantum computing",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(result.Text)
}
Anthropic Provider Errors
Error: "Invalid Authentication"
Symptoms:
Error: invalid x-api-key
Status Code: 401
Cause: Invalid or missing Anthropic API key.
Solution:
package main
import (
"context"
"fmt"
"log"
"os"
"strings"
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/anthropic"
)
func validateAnthropicKey(key string) error {
if key == "" {
return fmt.Errorf("API key is empty")
}
// Anthropic keys should start with "sk-ant-"
if !strings.HasPrefix(key, "sk-ant-") {
return fmt.Errorf("invalid Anthropic API key format (should start with 'sk-ant-')")
}
return nil
}
func main() {
apiKey := os.Getenv("ANTHROPIC_API_KEY")
// Validate key format before using
if err := validateAnthropicKey(apiKey); err != nil {
log.Fatalf("API key validation failed: %v", err)
}
provider := anthropic.New(anthropic.Config{
APIKey: apiKey,
})
model, err := provider.LanguageModel("claude-3-5-sonnet-20241022")
if err != nil {
log.Fatalf("Failed to create model: %v", err)
}
ctx := context.Background()
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: "Hello!",
})
if err != nil {
log.Fatalf("Failed to generate text: %v", err)
}
fmt.Println(result.Text)
}
Error: "Overloaded Error"
Symptoms:
Error: Overloaded
Status Code: 529
Cause: Anthropic's servers are temporarily overloaded.
Solution:
package main
import (
"context"
"errors"
"fmt"
"log"
"math"
"os"
"time"
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/provider"
providererrors "github.com/digitallysavvy/go-ai/pkg/provider/errors"
"github.com/digitallysavvy/go-ai/pkg/providers/anthropic"
)
func generateWithRetry(ctx context.Context, model provider.LanguageModel, prompt string, maxRetries int) (string, error) {
var lastErr error
for attempt := 0; attempt <= maxRetries; attempt++ {
if attempt > 0 {
// Exponential backoff with jitter
backoff := time.Duration(math.Pow(2, float64(attempt-1))) * time.Second
jitter := time.Duration(float64(backoff) * 0.1)
wait := backoff + jitter
log.Printf("Attempt %d/%d failed, waiting %v before retry...", attempt, maxRetries, wait)
select {
case <-time.After(wait):
case <-ctx.Done():
return "", ctx.Err()
}
}
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: prompt,
})
if err == nil {
return result.Text, nil
}
lastErr = err
// Check if error is retryable
var providerErr *providererrors.ProviderError
if errors.As(err, &providerErr) {
// Retry on 529 (overloaded) and 5xx errors
if providerErr.StatusCode == 529 || (providerErr.StatusCode >= 500 && providerErr.StatusCode < 600) {
log.Printf("Retryable error (status %d): %s", providerErr.StatusCode, providerErr.Message)
continue
}
// Don't retry on 4xx errors (except 429)
if providerErr.StatusCode >= 400 && providerErr.StatusCode < 500 && providerErr.StatusCode != 429 {
return "", fmt.Errorf("non-retryable error: %w", err)
}
}
}
return "", fmt.Errorf("failed after %d attempts: %w", maxRetries+1, lastErr)
}
func main() {
ctx := context.Background()
provider := anthropic.New(anthropic.Config{
APIKey: os.Getenv("ANTHROPIC_API_KEY"),
})
model, _ := provider.LanguageModel("claude-3-5-sonnet-20241022")
text, err := generateWithRetry(ctx, model, "Explain quantum computing", 5)
if err != nil {
log.Fatalf("Failed: %v", err)
}
fmt.Println(text)
}
Google (Gemini) Provider Errors
Error: "API Key Not Valid"
Symptoms:
Error: API key not valid. Please pass a valid API key
Status Code: 400
Cause: Invalid Google AI API key or using the wrong type of credentials.
Solution:
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/google"
)
func main() {
// Google AI Studio API key (not GCP service account)
apiKey := os.Getenv("GOOGLE_GENERATIVE_AI_API_KEY")
if apiKey == "" {
log.Fatal("GOOGLE_GENERATIVE_AI_API_KEY not set")
}
// For Google AI Studio (free tier)
provider := google.New(google.Config{
APIKey: apiKey,
})
model, err := provider.LanguageModel("gemini-1.5-pro")
if err != nil {
log.Fatalf("Failed to create model: %v", err)
}
ctx := context.Background()
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: "Hello!",
})
if err != nil {
log.Fatalf("Failed to generate text: %v", err)
}
fmt.Println(result.Text)
}
Error: "Resource Exhausted"
Symptoms:
Error: Resource has been exhausted (e.g. check quota)
Status Code: 429
Cause: Exceeded Google AI API quota (RPM or TPM limits).
Solution:
package main
import (
"context"
"errors"
"fmt"
"log"
"os"
"time"
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/provider"
providererrors "github.com/digitallysavvy/go-ai/pkg/provider/errors"
"github.com/digitallysavvy/go-ai/pkg/providers/google"
"golang.org/x/time/rate"
)
// Rate limiter for Google AI (15 RPM for free tier)
var googleLimiter = rate.NewLimiter(rate.Limit(15.0/60.0), 1)
func generateWithRateLimit(ctx context.Context, model provider.LanguageModel, prompt string) (string, error) {
// Wait for rate limiter
if err := googleLimiter.Wait(ctx); err != nil {
return "", fmt.Errorf("rate limiter error: %w", err)
}
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: prompt,
})
if err != nil {
var rateLimitErr *providererrors.RateLimitError
if errors.As(err, &rateLimitErr) {
// Wait and retry if rate limited
if rateLimitErr.RetryAfterSeconds != nil {
waitDuration := time.Duration(*rateLimitErr.RetryAfterSeconds) * time.Second
log.Printf("Rate limited, waiting %v...", waitDuration)
select {
case <-time.After(waitDuration):
return generateWithRateLimit(ctx, model, prompt)
case <-ctx.Done():
return "", ctx.Err()
}
}
}
return "", err
}
return result.Text, nil
}
func main() {
ctx := context.Background()
provider := google.New(google.Config{
APIKey: os.Getenv("GOOGLE_GENERATIVE_AI_API_KEY"),
})
model, _ := provider.LanguageModel("gemini-1.5-flash")
text, err := generateWithRateLimit(ctx, model, "Explain quantum computing")
if err != nil {
log.Fatalf("Failed: %v", err)
}
fmt.Println(text)
}
Azure OpenAI Provider Errors
Error: "Deployment Not Found"
Symptoms:
Error: The API deployment for this resource does not exist
Status Code: 404
Cause: Using incorrect deployment name or endpoint URL.
Solution:
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/azure"
)
func main() {
// Azure OpenAI requires resource, key, and deployment configuration.
resourceName := os.Getenv("AZURE_RESOURCE_NAME")
apiKey := os.Getenv("AZURE_API_KEY")
deployment := os.Getenv("AZURE_OPENAI_DEPLOYMENT") // e.g., "gpt-5-mini"
if resourceName == "" || apiKey == "" || deployment == "" {
log.Fatal("Missing Azure OpenAI configuration (resource name, key, or deployment)")
}
provider, err := azure.New(azure.Config{
ResourceName: resourceName,
APIKey: apiKey,
UseDeploymentBasedURLs: true,
})
if err != nil {
log.Fatalf("Failed to create provider: %v", err)
}
// Use the deployment name, not the model name
model, err := provider.LanguageModel(deployment)
if err != nil {
log.Fatalf("Failed to create model: %v", err)
}
ctx := context.Background()
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: "Hello!",
})
if err != nil {
log.Fatalf("Failed to generate text: %v", err)
}
fmt.Println(result.Text)
}
AWS Bedrock Provider Errors
Error: "Access Denied"
Symptoms:
Error: User is not authorized to perform: bedrock:InvokeModel
Status Code: 403
Cause: IAM credentials don't have permission to access Bedrock.
Solution:
package main
import (
"context"
"fmt"
"log"
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/bedrock"
)
func main() {
ctx := context.Background()
// bedrock.Config signs requests itself (SigV4), so there is no AWS SDK
// aws.Config to load. With AWSAccessKeyID/AWSSecretAccessKey left unset,
// credentials and region fall back to the environment (AWS_REGION,
// AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY), the shared credentials file,
// or an instance role — the same chain the AWS CLI uses.
provider := bedrock.New(bedrock.Config{
Region: "us-east-1",
})
// Use full model ARN or ID
model, err := provider.LanguageModel("anthropic.claude-3-5-sonnet-20241022-v2:0")
if err != nil {
log.Fatalf("Failed to create model: %v", err)
}
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: "Hello!",
})
if err != nil {
log.Fatalf("Failed to generate text: %v", err)
}
fmt.Println(result.Text)
}
Required IAM Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": "*"
}
]
}
Network and Connection Errors
Error: "Connection Timeout"
Symptoms:
Error: context deadline exceeded
Error: dial tcp: i/o timeout
Cause: Network connectivity issues or firewall blocking API requests.
Solution:
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"time"
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
)
func main() {
// Create HTTP client with custom timeout
httpClient := &http.Client{
Timeout: 2 * time.Minute,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
},
}
provider := openai.New(openai.Config{
APIKey: os.Getenv("OPENAI_API_KEY"),
HTTPClient: httpClient,
})
model, _ := provider.LanguageModel("gpt-4")
// Use context with longer timeout
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
defer cancel()
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: "Write a long essay",
})
if err != nil {
log.Fatalf("Failed: %v", err)
}
fmt.Println(result.Text)
}
Best Practices
1. Implement Provider Fallback
providers := []struct {
name string
provider interface{}
model string
}{
{"openai", openaiProvider, "gpt-4o-mini"},
{"anthropic", anthropicProvider, "claude-3-5-haiku-20241022"},
{"google", googleProvider, "gemini-1.5-flash"},
}
for _, p := range providers {
result, err := tryGenerate(p.provider, p.model, prompt)
if err == nil {
return result
}
log.Printf("Provider %s failed: %v", p.name, err)
}
2. Validate Configuration at Startup
func validateConfig() error {
required := map[string]string{
"OPENAI_API_KEY": os.Getenv("OPENAI_API_KEY"),
}
for key, value := range required {
if value == "" {
return fmt.Errorf("missing required env var: %s", key)
}
}
return nil
}
3. Log Provider Errors with Context
if err != nil {
var providerErr *providererrors.ProviderError
if errors.As(err, &providerErr) {
log.Printf("Provider %s error (status %d): %s [code: %s]",
providerErr.Provider,
providerErr.StatusCode,
providerErr.Message,
providerErr.ErrorCode,
)
}
}
4. Monitor Provider Health
type ProviderHealth struct {
Name string
Healthy bool
LastCheck time.Time
ErrorCount int
}
func checkProviderHealth(provider interface{}, model string) ProviderHealth {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
_, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: "test",
MaxTokens: 5,
})
return ProviderHealth{
Healthy: err == nil,
LastCheck: time.Now(),
}
}