Common Errors
This guide covers the most common errors you'll encounter when using the Go AI SDK and how to fix them.
API Key Issues
Error: "Invalid API Key"
Symptoms:
Error: provider error (401): Invalid API key provided
Error: authentication failed
Cause: The API key is missing, incorrect, or not properly loaded from environment variables.
Solution:
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
)
func main() {
// Check if API key is set
apiKey := os.Getenv("OPENAI_API_KEY")
if apiKey == "" {
log.Fatal("OPENAI_API_KEY environment variable not set")
}
// Verify key is not empty or whitespace
if len(apiKey) < 20 {
log.Fatal("OPENAI_API_KEY appears to be invalid (too short)")
}
provider := openai.New(openai.Config{
APIKey: apiKey,
})
model, err := provider.LanguageModel("gpt-4")
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)
}
Best Practices:
- Use environment variables for API keys (never hardcode)
- Use
.envfiles withgodotenvfor local development - Validate API keys on application startup
- Use separate keys for development and production
Error: "Model Not Found"
Symptoms:
Error: model "gpt-5" not found
Error: invalid model specified
Cause: Trying to use a model that doesn't exist or isn't available in your account.
Solution:
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
)
func main() {
ctx := context.Background()
provider := openai.New(openai.Config{
APIKey: os.Getenv("OPENAI_API_KEY"),
})
// Use valid model names
validModels := []string{
"gpt-4",
"gpt-4-turbo",
"gpt-4o",
"gpt-4o-mini",
"gpt-3.5-turbo",
}
log.Printf("known-good model names: %v", validModels)
// Try to create model with error handling
model, err := provider.LanguageModel("gpt-4")
if err != nil {
log.Printf("Failed to create gpt-4 model: %v", err)
log.Println("Falling back to gpt-4o-mini...")
model, err = provider.LanguageModel("gpt-4o-mini")
if err != nil {
log.Fatalf("Failed to create fallback 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)
}
Nil Pointer Errors
Error: "nil pointer dereference"
Symptoms:
panic: runtime error: invalid memory address or nil pointer dereference
Cause: Not checking for errors before using returned values, or accessing fields on nil structs.
Solution:
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
)
func main() {
ctx := context.Background()
provider := openai.New(openai.Config{
APIKey: os.Getenv("OPENAI_API_KEY"),
})
// ALWAYS check errors before using the returned value
model, err := provider.LanguageModel("gpt-4")
if err != nil {
log.Fatalf("Failed to create model: %v", err)
}
// Now it's safe to use model
// Check result is not nil before accessing fields
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: "Hello!",
})
if err != nil {
log.Fatalf("Failed to generate text: %v", err)
}
// Safe to access result.Text now
if result != nil {
fmt.Println(result.Text)
}
}
Channel and Streaming Errors
Error: "Channel Already Closed"
Symptoms:
panic: send on closed channel
panic: close of closed channel
Cause: Trying to read from a stream channel multiple times or not properly handling channel closure.
Solution:
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
)
func main() {
ctx := context.Background()
provider := openai.New(openai.Config{
APIKey: os.Getenv("OPENAI_API_KEY"),
})
model, _ := provider.LanguageModel("gpt-4")
stream, err := ai.StreamText(ctx, ai.StreamTextOptions{
Model: model,
Prompt: "Write a short story",
})
if err != nil {
log.Fatal(err)
}
// Read from channel until it closes
// The range loop automatically handles channel closure
for chunk := range stream.Chunks() {
fmt.Print(chunk.Text)
}
// Channel is now closed - DO NOT try to read again
// Check for errors after stream completes
if err := stream.Err(); err != nil {
log.Printf("Stream error: %v", err)
}
// DO NOT try to read from Chunks again - it's closed
}
Error: "Goroutine Leak / Stream Not Consumed"
Symptoms:
- Application hangs indefinitely
- Memory usage grows over time
- Goroutines never terminate
Cause: Not consuming all values from a stream channel, causing the goroutine to block.
Solution:
package main
import (
"context"
"fmt"
"log"
"os"
"time"
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/provider"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
)
func processStream(ctx context.Context, model provider.LanguageModel, prompt string) error {
stream, err := ai.StreamText(ctx, ai.StreamTextOptions{
Model: model,
Prompt: prompt,
})
if err != nil {
return err
}
// ALWAYS consume the entire stream, even if you don't need all the data
for chunk := range stream.Chunks() {
fmt.Print(chunk.Text)
// If you need to exit early, the context will cancel the stream
select {
case <-ctx.Done():
// Stream will be automatically cleaned up
return ctx.Err()
default:
// Continue processing
}
}
return stream.Err()
}
func main() {
// Use context with timeout to prevent infinite hangs
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
provider := openai.New(openai.Config{
APIKey: os.Getenv("OPENAI_API_KEY"),
})
model, _ := provider.LanguageModel("gpt-4")
if err := processStream(ctx, model, "Write a story"); err != nil {
log.Printf("Error: %v", err)
}
}
Import Errors
Error: "Package Not Found"
Symptoms:
cannot find package "github.com/digitallysavvy/go-ai/pkg/ai"
Cause:
Module not downloaded or go.mod not properly initialized.
Solution:
# Initialize module (if not already done)
go mod init your-project-name
# Install the Go AI SDK
go get github.com/digitallysavvy/go-ai
# Tidy up dependencies
go mod tidy
# Verify installation
go list -m github.com/digitallysavvy/go-ai
Error: "Ambiguous Import"
Symptoms:
ambiguous import: found package in multiple locations
Cause: Conflicting package names or vendored dependencies.
Solution:
package main
import (
"context"
// Use full import paths with aliases if needed
goai "github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
// If you have naming conflicts, use aliases
aitools "github.com/digitallysavvy/go-ai/pkg/provider/types"
)
func main() {
ctx := context.Background()
_ = aitools.RoleUser // use the aliased import, same as any other import
model, _ := openai.New(openai.Config{}).LanguageModel("gpt-4o")
// Use aliases in your code
result, err := goai.GenerateText(ctx, goai.GenerateTextOptions{
Model: model,
Prompt: "Hello!",
})
_ = result
_ = err
}
Type Errors
Error: "Type Mismatch"
Symptoms:
cannot use X (type string) as type interface in argument
cannot convert X to type Y
Cause: Passing wrong types to SDK functions.
Solution:
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/provider/types"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
)
func main() {
ctx := context.Background()
provider := openai.New(openai.Config{
APIKey: os.Getenv("OPENAI_API_KEY"),
})
model, _ := provider.LanguageModel("gpt-4")
// CORRECT: Pass messages as proper types.Message slice, with Content
// as a []types.ContentPart, not a bare string
messages := []types.Message{
{
Role: types.RoleUser,
Content: []types.ContentPart{types.TextContent{Text: "Hello!"}},
},
}
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Messages: messages, // Not strings
})
if err != nil {
log.Fatal(err)
}
fmt.Println(result.Text)
}
JSON Schema Errors
Error: "Schema Validation Failed"
Symptoms:
Error: schema validation failed: invalid type for field X
Error: generated object does not match schema
Cause: JSON schema doesn't match your Go struct, or schema is invalid.
Solution:
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
goschema "github.com/digitallysavvy/go-ai/pkg/schema"
"github.com/invopop/jsonschema"
)
// Define struct with proper JSON tags
type Recipe struct {
Name string `json:"name" jsonschema:"required,description=Name of the recipe"`
Ingredients []string `json:"ingredients" jsonschema:"required,minItems=1,description=List of ingredients"`
Steps []string `json:"steps" jsonschema:"required,minItems=1,description=Cooking steps"`
PrepTime int `json:"prepTime" jsonschema:"minimum=0,description=Preparation time in minutes"`
}
func main() {
ctx := context.Background()
provider := openai.New(openai.Config{
APIKey: os.Getenv("OPENAI_API_KEY"),
})
model, _ := provider.LanguageModel("gpt-4")
// Generate a JSON schema from the struct with invopop/jsonschema, then
// wrap the resulting map in goschema.Schema — ai.GenerateObjectOptions.Schema
// takes a schema.Schema, not a *jsonschema.Schema directly.
reflector := jsonschema.Reflector{
AllowAdditionalProperties: false,
DoNotReference: true,
}
reflected := reflector.Reflect(&Recipe{})
schemaBytes, err := json.Marshal(reflected)
if err != nil {
log.Fatalf("Invalid schema: %v", err)
}
log.Printf("Using schema:\n%s", schemaBytes)
var schemaMap map[string]interface{}
if err := json.Unmarshal(schemaBytes, &schemaMap); err != nil {
log.Fatalf("Failed to decode schema: %v", err)
}
var recipe Recipe
if err := ai.GenerateObjectInto(ctx, ai.GenerateObjectOptions{
Model: model,
Schema: goschema.NewSimpleJSONSchema(schemaMap),
Prompt: "Generate a lasagna recipe",
}, &recipe); err != nil {
log.Fatalf("Failed to generate object: %v", err)
}
fmt.Printf("Recipe: %s\n", recipe.Name)
}
Context Errors
Error: "Context Deadline Exceeded"
Symptoms:
Error: context deadline exceeded
Request timed out
Cause: Operation took longer than the context timeout allows.
Solution:
package main
import (
"context"
"fmt"
"log"
"os"
"time"
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
)
func main() {
provider := openai.New(openai.Config{
APIKey: os.Getenv("OPENAI_API_KEY"),
})
model, _ := provider.LanguageModel("gpt-4")
// Increase timeout for long operations
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: "Write a detailed 5000-word essay on quantum computing",
})
if err != nil {
if ctx.Err() == context.DeadlineExceeded {
log.Println("Operation timed out - increase the timeout or use streaming")
// Alternative: Use streaming for long responses
stream, err := ai.StreamText(context.Background(), ai.StreamTextOptions{
Model: model,
Prompt: "Write a detailed 5000-word essay on quantum computing",
})
if err != nil {
log.Fatal(err)
}
for chunk := range stream.Chunks() {
fmt.Print(chunk.Text)
}
if err := stream.Err(); err != nil {
log.Fatal(err)
}
return
}
log.Fatalf("Error: %v", err)
}
fmt.Println(result.Text)
}
Best Practices
1. Always Check Errors
// Bad
result, _ := ai.GenerateText(ctx, options)
// Good
result, err := ai.GenerateText(ctx, options)
if err != nil {
return fmt.Errorf("generation failed: %w", err)
}
2. Use Context Timeouts
// Always use context with timeout for production
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
3. Consume Streams Completely
// Always read all values from stream channels
for chunk := range stream.Chunks() {
// Process chunk
}
// Check error after stream closes
if err := stream.Err(); err != nil {
log.Printf("Stream error: %v", err)
}
4. Validate Configuration
// Check configuration at startup
if apiKey := os.Getenv("OPENAI_API_KEY"); apiKey == "" {
log.Fatal("Missing OPENAI_API_KEY")
}
5. Use Proper Types
// Use SDK types, not raw strings
messages := []types.Message{
{Role: types.RoleUser, Content: "Hello"},
}