errors

package
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 8, 2026 License: MIT Imports: 11 Imported by: 0

README

Error Handling Framework

A comprehensive error handling framework for AINative Code with custom error types, wrapping/unwrapping support, stack traces, and recovery strategies.

Table of Contents

Overview

The error handling framework provides:

  • Custom Error Types: Specialized errors for different domains (Config, Auth, Provider, Tool, Database)
  • Error Wrapping: Chain errors while preserving context
  • Stack Traces: Capture call stacks in debug mode
  • User-Friendly Messages: Separate technical and user-facing error messages
  • Retry Strategies: Built-in retry mechanisms with exponential backoff
  • Circuit Breaker: Prevent cascading failures
  • Structured Errors: JSON serialization for APIs

Error Types

ConfigError

Configuration-related errors for invalid, missing, or malformed configuration.

// Missing configuration
err := errors.NewConfigMissingError("api_key")

// Invalid configuration
err := errors.NewConfigInvalidError("timeout", "must be a positive integer")

// Parse error
err := errors.NewConfigParseError("/path/to/config.yaml", cause)

// Validation error
err := errors.NewConfigValidationError("port", "must be between 1 and 65535")
AuthenticationError

Authentication and authorization errors.

// General auth failure
err := errors.NewAuthFailedError("openai", cause)

// Invalid token
err := errors.NewInvalidTokenError("anthropic")

// Expired token (retryable)
err := errors.NewExpiredTokenError("google")

// Permission denied
err := errors.NewPermissionDeniedError("/api/users", "delete")

// Invalid credentials
err := errors.NewInvalidCredentialsError("aws")
ProviderError

Errors related to external AI provider interactions.

// Provider unavailable (retryable)
err := errors.NewProviderUnavailableError("openai", cause)

// Timeout (retryable)
err := errors.NewProviderTimeoutError("anthropic", "claude-3", 30*time.Second)

// Rate limit (retryable with delay)
err := errors.NewProviderRateLimitError("openai", 60*time.Second)

// Invalid response (retryable)
err := errors.NewProviderInvalidResponseError("google", "malformed JSON", cause)

// Provider not found
err := errors.NewProviderNotFoundError("unknown-provider")
ToolExecutionError

Errors during tool execution.

// Tool not found
err := errors.NewToolNotFoundError("git")

// Execution failed
err := errors.NewToolExecutionFailedError("git", 128, output, cause)

// Timeout (retryable)
err := errors.NewToolTimeoutError("terraform", 30*time.Second)

// Invalid input
err := errors.NewToolInvalidInputError("docker", "image", "must not be empty")

// Permission denied
err := errors.NewToolPermissionDeniedError("kubectl", "/etc/kubernetes/config")
DatabaseError

Database-related errors.

// Connection error (retryable)
err := errors.NewDBConnectionError("postgres", cause)

// Query error
err := errors.NewDBQueryError("SELECT", "users", cause)

// Not found
err := errors.NewDBNotFoundError("products", "id=123")

// Duplicate entry
err := errors.NewDBDuplicateError("users", "email", "test@example.com")

// Constraint violation
err := errors.NewDBConstraintError("orders", "fk_user_id", cause)

// Transaction error (retryable)
err := errors.NewDBTransactionError("commit", cause)

Features

Error Wrapping and Unwrapping
// Wrap an error with additional context
originalErr := errors.New("connection refused")
wrappedErr := errors.Wrap(originalErr, errors.ErrCodeDBConnection, "failed to connect to database")

// Wrap with formatted message
wrappedErr := errors.Wrapf(originalErr, errors.ErrCodeDBConnection, "failed to connect to %s", dbName)

// Unwrap to get the original error
var baseErr *errors.BaseError
if errors.As(wrappedErr, &baseErr) {
    original := baseErr.Unwrap()
}

// Get the root cause
rootErr := errors.RootCause(wrappedErr)
Stack Traces (Debug Mode)
// Enable debug mode to capture stack traces
errors.EnableDebugMode()

// Create an error - stack trace is automatically captured
err := errors.NewConfigInvalidError("api_key", "must not be empty")

// Format with stack trace
formatted := errors.Format(err)
// Output includes file, line, and function information

// Get just the stack trace
stackTrace := err.StackTrace()
User-Friendly Messages
// Errors have both technical and user-facing messages
err := errors.NewConfigMissingError("database_url")

// Technical message (for logs)
technical := err.Error()
// Output: [CONFIG_MISSING] Required configuration 'database_url' is missing

// User-friendly message (for UI)
userMsg := err.UserMessage()
// Output: Configuration error: Required setting 'database_url' is not configured. Please check your configuration file.

// Or use the helper
userMsg := errors.FormatUser(err)
Error Metadata
err := errors.NewProviderTimeoutError("openai", "gpt-4", 30*time.Second)

// Add metadata
err.WithMetadata("request_id", "req-123")
err.WithMetadata("user_id", "user-456")
err.WithMetadata("timestamp", time.Now())

// Retrieve metadata
metadata := err.Metadata()
requestID := metadata["request_id"]
JSON Serialization
err := errors.NewAuthFailedError("openai", cause)

// Convert to JSON (for API responses)
jsonData, _ := errors.ToJSON(err)

// Parse from JSON
deserializedErr := errors.FromJSON(jsonData)

Error Recovery

Retry with Exponential Backoff
ctx := context.Background()
config := errors.NewRetryConfig()

// Customize retry strategy
config.Strategy = errors.NewExponentialBackoff()
config.OnRetry = func(attempt int, err error) {
    log.Printf("Retry attempt %d: %v", attempt, err)
}

// Execute with retry
err := errors.Retry(ctx, func() error {
    return callExternalAPI()
}, config)
Linear Backoff
// Retry with constant delay
config := errors.NewRetryConfig()
config.Strategy = errors.NewLinearBackoff(1*time.Second, 3)

err := errors.Retry(ctx, func() error {
    return performOperation()
}, config)
Circuit Breaker
// Create circuit breaker (max 3 failures, 30s reset timeout)
cb := errors.NewCircuitBreaker(3, 30*time.Second)

// Execute through circuit breaker
err := cb.Execute(func() error {
    return callUnreliableService()
})

// Check circuit state
if cb.GetState() == errors.StateOpen {
    log.Println("Circuit is open, requests blocked")
}

// Manual reset
cb.Reset()
Fallback Strategies
// Simple fallback
err := errors.Fallback(
    func() error {
        return primaryOperation()
    },
    func() error {
        return fallbackOperation()
    },
)

// Fallback with value
result, err := errors.FallbackWithValue(
    func() (string, error) {
        return fetchFromPrimary()
    },
    "default value",
)

Usage Examples

Complete Example: API Call with Retry and Circuit Breaker
package main

import (
    "context"
    "time"
    "github.com/ainative/ainative-code/internal/errors"
)

type APIClient struct {
    cb *errors.CircuitBreaker
}

func NewAPIClient() *APIClient {
    return &APIClient{
        cb: errors.NewCircuitBreaker(5, 30*time.Second),
    }
}

func (c *APIClient) CallAPI(ctx context.Context, endpoint string) error {
    config := errors.NewRetryConfig()
    config.Strategy = errors.NewExponentialBackoff()

    config.OnRetry = func(attempt int, err error) {
        log.Printf("Retrying API call to %s (attempt %d): %v", endpoint, attempt, err)
    }

    return errors.Retry(ctx, func() error {
        return c.cb.Execute(func() error {
            resp, err := http.Get(endpoint)
            if err != nil {
                return errors.NewProviderUnavailableError("api", err)
            }
            defer resp.Body.Close()

            if resp.StatusCode == 429 {
                retryAfter := parseRetryAfter(resp.Header)
                return errors.NewProviderRateLimitError("api", retryAfter)
            }

            if resp.StatusCode >= 500 {
                return errors.NewProviderUnavailableError("api",
                    fmt.Errorf("server error: %d", resp.StatusCode))
            }

            return nil
        })
    }, config)
}
Database Operation with Error Handling
func GetUser(ctx context.Context, db *sql.DB, userID string) (*User, error) {
    var user User

    err := db.QueryRowContext(ctx, "SELECT * FROM users WHERE id = $1", userID).Scan(&user)
    if err != nil {
        if err == sql.ErrNoRows {
            return nil, errors.NewDBNotFoundError("users", fmt.Sprintf("id=%s", userID))
        }
        return nil, errors.Wrap(err, errors.ErrCodeDBQuery, "failed to fetch user")
    }

    return &user, nil
}

func CreateUser(ctx context.Context, db *sql.DB, user *User) error {
    _, err := db.ExecContext(ctx,
        "INSERT INTO users (id, email, name) VALUES ($1, $2, $3)",
        user.ID, user.Email, user.Name)

    if err != nil {
        // Check for duplicate key error
        if isDuplicateKeyError(err) {
            return errors.NewDBDuplicateError("users", "email", user.Email)
        }
        return errors.Wrap(err, errors.ErrCodeDBQuery, "failed to create user")
    }

    return nil
}
HTTP API Error Response
func errorResponse(w http.ResponseWriter, err error) {
    // Get error code and severity
    code := errors.GetCode(err)
    severity := errors.GetSeverity(err)

    // Determine HTTP status code
    var statusCode int
    switch code {
    case errors.ErrCodeDBNotFound, errors.ErrCodeProviderNotFound:
        statusCode = http.StatusNotFound
    case errors.ErrCodeAuthFailed, errors.ErrCodeAuthInvalidToken:
        statusCode = http.StatusUnauthorized
    case errors.ErrCodeAuthPermissionDenied:
        statusCode = http.StatusForbidden
    case errors.ErrCodeProviderRateLimit:
        statusCode = http.StatusTooManyRequests
    default:
        statusCode = http.StatusInternalServerError
    }

    // Convert to JSON
    jsonData, _ := errors.ToJSON(err)

    // Log technical details
    if severity == errors.SeverityCritical || severity == errors.SeverityHigh {
        log.Printf("Error: %s", errors.Format(err))
    }

    // Send user-friendly response
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(statusCode)
    w.Write(jsonData)
}

Best Practices

1. Use Specific Error Types
// Good: Use specific error constructors
err := errors.NewConfigMissingError("api_key")

// Avoid: Using generic errors
err := fmt.Errorf("api_key is missing")
2. Wrap Errors at Boundaries
// Wrap errors when crossing layer boundaries
func (s *Service) GetUser(id string) (*User, error) {
    user, err := s.repo.FindByID(id)
    if err != nil {
        return nil, errors.Wrap(err, errors.ErrCodeDBQuery, "service: failed to get user")
    }
    return user, nil
}
3. Use Debug Mode in Development
// In main.go or initialization
if os.Getenv("ENV") == "development" {
    errors.EnableDebugMode()
}
4. Always Check Retryability
if errors.IsRetryable(err) {
    // Implement retry logic
} else {
    // Fail immediately
}
5. Provide User-Friendly Messages
// Always set user-friendly messages for end-user facing errors
err := errors.NewAuthFailedError("provider", cause)
// The constructor already provides a good user message

// Display to user
fmt.Println(err.UserMessage())
6. Add Context with Metadata
err := errors.NewProviderTimeoutError("openai", "gpt-4", 30*time.Second)
err.WithMetadata("request_id", requestID)
err.WithMetadata("user_id", userID)
err.WithMetadata("endpoint", endpoint)

API Reference

Error Codes
  • Config: ErrCodeConfigInvalid, ErrCodeConfigMissing, ErrCodeConfigParse, ErrCodeConfigValidation
  • Auth: ErrCodeAuthFailed, ErrCodeAuthInvalidToken, ErrCodeAuthExpiredToken, ErrCodeAuthPermissionDenied, ErrCodeAuthInvalidCredentials
  • Provider: ErrCodeProviderUnavailable, ErrCodeProviderTimeout, ErrCodeProviderRateLimit, ErrCodeProviderInvalidResponse, ErrCodeProviderNotFound
  • Tool: ErrCodeToolNotFound, ErrCodeToolExecutionFailed, ErrCodeToolTimeout, ErrCodeToolInvalidInput, ErrCodeToolPermissionDenied
  • Database: ErrCodeDBConnection, ErrCodeDBQuery, ErrCodeDBNotFound, ErrCodeDBDuplicate, ErrCodeDBConstraint, ErrCodeDBTransaction
Severity Levels
  • SeverityLow: Minor issues, informational
  • SeverityMedium: Standard errors
  • SeverityHigh: Serious errors requiring attention
  • SeverityCritical: Critical failures, system-level issues
Key Functions
  • Wrap(err, code, message): Wrap error with context
  • Wrapf(err, code, format, args...): Wrap with formatted message
  • GetCode(err): Extract error code
  • IsRetryable(err): Check if error is retryable
  • GetSeverity(err): Get error severity
  • Format(err): Format for logging (includes stack in debug mode)
  • FormatUser(err): Get user-friendly message
  • ToJSON(err): Serialize to JSON
  • FromJSON(data): Deserialize from JSON
  • RootCause(err): Get the root cause of wrapped errors
Retry Strategies
  • NewExponentialBackoff(): Exponential backoff with sensible defaults
  • NewLinearBackoff(delay, maxRetries): Constant delay between retries
  • Retry(ctx, fn, config): Execute function with retry logic
  • NewCircuitBreaker(maxFailures, resetTimeout): Create circuit breaker
  • Fallback(primary, fallback): Execute with fallback

Copyright © 2024 AINative Studio. All rights reserved.

Documentation

Overview

Package errors provides a comprehensive error handling framework for AINative Code. It includes custom error types, error wrapping/unwrapping, stack traces, and recovery strategies.

Example (AuthenticationError)

Example demonstrates authentication error

package main

import (
	"fmt"

	"github.com/AINative-studio/ainative-code/internal/errors"
)

func main() {
	err := errors.NewExpiredTokenError("google")

	fmt.Println("Error:", err.Error())
	fmt.Println("Provider:", err.Provider)
	fmt.Println("Can retry:", err.IsRetryable())
	fmt.Println("User message:", err.UserMessage())

}
Output:

Error: [AUTH_EXPIRED_TOKEN] Authentication token expired for provider 'google'
Provider: google
Can retry: true
User message: Authentication error: Your session has expired. Please log in again.
Example (BasicUsage)

Example demonstrates basic error creation and handling

package main

import (
	"fmt"

	"github.com/AINative-studio/ainative-code/internal/errors"
)

func main() {
	// Create a configuration error
	err := errors.NewConfigMissingError("api_key")

	// Get technical error message (for logging)
	fmt.Println("Technical:", err.Error())

	// Get user-friendly message (for UI display)
	fmt.Println("User:", err.UserMessage())

	// Check error properties
	fmt.Println("Code:", err.Code())
	fmt.Println("Severity:", err.Severity())
	fmt.Println("Retryable:", err.IsRetryable())

}
Output:

Technical: [CONFIG_MISSING] Required configuration 'api_key' is missing
User: Configuration error: Required setting 'api_key' is not configured. Please check your configuration file.
Code: CONFIG_MISSING
Severity: high
Retryable: false
Example (CircuitBreaker)

Example demonstrates circuit breaker pattern

package main

import (
	"fmt"
	"time"

	"github.com/AINative-studio/ainative-code/internal/errors"
)

func main() {
	// Create circuit breaker (max 2 failures, 100ms reset)
	cb := errors.NewCircuitBreaker(2, 100*time.Millisecond)

	// Simulate failing operation
	for i := 0; i < 3; i++ {
		err := cb.Execute(func() error {
			return fmt.Errorf("service unavailable")
		})

		if err != nil {
			if cb.GetState() == errors.StateOpen {
				fmt.Println("Circuit opened")
				break
			}
		}
	}

	// Circuit is now open
	err := cb.Execute(func() error {
		return nil
	})

	if err != nil {
		fmt.Println("Request blocked:", err.Error())
	}

}
Output:

Circuit opened
Request blocked: circuit breaker is open: too many failures
Example (DatabaseError)

Example demonstrates database error handling

package main

import (
	"fmt"

	"github.com/AINative-studio/ainative-code/internal/errors"
)

func main() {
	// Not found error
	notFoundErr := errors.NewDBNotFoundError("users", "id=123")
	fmt.Println("Not found:", notFoundErr.UserMessage())

	// Duplicate entry error
	dupErr := errors.NewDBDuplicateError("users", "email", "test@example.com")
	fmt.Println("Duplicate:", dupErr.UserMessage())

}
Output:

Not found: Not found: The requested resource does not exist.
Duplicate: Duplicate entry: A record with this email already exists.
Example (ErrorCodes)

Example demonstrates error code extraction

package main

import (
	"fmt"
	"time"

	"github.com/AINative-studio/ainative-code/internal/errors"
)

func main() {
	configErr := errors.NewConfigInvalidError("timeout", "must be positive")
	authErr := errors.NewAuthFailedError("provider", nil)
	providerErr := errors.NewProviderRateLimitError("openai", 60*time.Second)

	fmt.Println("Config:", errors.GetCode(configErr))
	fmt.Println("Auth:", errors.GetCode(authErr))
	fmt.Println("Provider:", errors.GetCode(providerErr))

}
Output:

Config: CONFIG_INVALID
Auth: AUTH_FAILED
Provider: PROVIDER_RATE_LIMIT
Example (ErrorSeverity)

Example demonstrates error severity checking

package main

import (
	"fmt"

	"github.com/AINative-studio/ainative-code/internal/errors"
)

func main() {
	criticalErr := errors.NewDBConnectionError("postgres", fmt.Errorf("refused"))
	highErr := errors.NewConfigMissingError("database_url")
	mediumErr := errors.NewDBDuplicateError("users", "email", "test@example.com")
	lowErr := errors.NewDBNotFoundError("products", "id=999")

	fmt.Println("Critical:", errors.GetSeverity(criticalErr))
	fmt.Println("High:", errors.GetSeverity(highErr))
	fmt.Println("Medium:", errors.GetSeverity(mediumErr))
	fmt.Println("Low:", errors.GetSeverity(lowErr))

}
Output:

Critical: critical
High: high
Medium: medium
Low: low
Example (ErrorWrapping)

Example demonstrates error wrapping

package main

import (
	"fmt"

	"github.com/AINative-studio/ainative-code/internal/errors"
)

func main() {
	// Simulate a lower-level error
	dbErr := fmt.Errorf("connection refused")

	// Wrap it with context
	wrappedErr := errors.Wrap(dbErr, errors.ErrCodeDBConnection, "failed to connect to database")

	fmt.Println(wrappedErr)

}
Output:

[DB_CONNECTION_FAILED] failed to connect to database: connection refused
Example (Fallback)

Example demonstrates fallback pattern

package main

import (
	"fmt"

	"github.com/AINative-studio/ainative-code/internal/errors"
)

func main() {
	// Try primary operation, fall back to alternative
	err := errors.Fallback(
		func() error {
			return fmt.Errorf("primary service unavailable")
		},
		func() error {
			fmt.Println("Using fallback service")
			return nil
		},
	)

	if err == nil {
		fmt.Println("Operation succeeded")
	}

}
Output:

Using fallback service
Operation succeeded
Example (ProviderErrorWithMetadata)

Example demonstrates provider error with metadata

package main

import (
	"fmt"
	"time"

	"github.com/AINative-studio/ainative-code/internal/errors"
)

func main() {
	err := errors.NewProviderTimeoutError("openai", "gpt-4", 30*time.Second)
	err.WithMetadata("request_id", "req-123456")
	err.WithMetadata("user_id", "user-789")

	fmt.Println("Provider:", err.ProviderName)
	fmt.Println("Model:", err.Model)
	fmt.Println("Retryable:", err.IsRetryable())

	metadata := err.Metadata()
	fmt.Println("Request ID:", metadata["request_id"])

}
Output:

Provider: openai
Model: gpt-4
Retryable: true
Request ID: req-123456
Example (RetryWithBackoff)

Example demonstrates retry with exponential backoff

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/AINative-studio/ainative-code/internal/errors"
)

func main() {
	ctx := context.Background()

	// Configure retry strategy
	config := errors.NewRetryConfig()
	config.Strategy = errors.NewLinearBackoff(10*time.Millisecond, 3)

	callCount := 0
	config.OnRetry = func(attempt int, err error) {
		fmt.Printf("Retry attempt %d failed\n", attempt+1)
	}

	// Simulate an operation that fails twice then succeeds
	err := errors.Retry(ctx, func() error {
		callCount++
		if callCount < 3 {
			return errors.NewProviderTimeoutError("api", "model", 30*time.Second)
		}
		return nil
	}, config)

	if err != nil {
		fmt.Println("Failed after all retries")
	} else {
		fmt.Printf("Success after %d total attempts\n", callCount)
	}

}
Output:

Retry attempt 1 failed
Retry attempt 2 failed
Success after 3 total attempts
Example (ToolExecutionError)

Example demonstrates tool execution error

package main

import (
	"fmt"

	"github.com/AINative-studio/ainative-code/internal/errors"
)

func main() {
	err := errors.NewToolNotFoundError("git")
	err.WithPath("/usr/bin/git")

	fmt.Println("Error:", err.Error())
	fmt.Println("Tool:", err.ToolName)
	fmt.Println("Path:", err.ToolPath)
	fmt.Println("User message:", err.UserMessage())

}
Output:

Error: [TOOL_NOT_FOUND] Tool 'git' not found
Tool: git
Path: /usr/bin/git
User message: Tool error: 'git' is not available or not installed. Please verify the tool is properly configured.

Index

Examples

Constants

This section is empty.

Variables

View Source
var DebugMode = false

DebugMode controls whether stack traces are included in error output

Functions

func As

func As(err error, target interface{}) bool

As finds the first error in err's chain that matches target

func Chain

func Chain(err error) []error

Chain returns all errors in the error chain

func DisableDebugMode

func DisableDebugMode()

DisableDebugMode disables debug mode

func EnableDebugMode

func EnableDebugMode()

EnableDebugMode enables debug mode with stack traces

func ExampleAdvancedCircuitBreaker_usage

func ExampleAdvancedCircuitBreaker_usage()

Example: Advanced circuit breaker with error-specific thresholds

func ExampleProviderRecoveryStrategy_apiKeyResolution

func ExampleProviderRecoveryStrategy_apiKeyResolution()

Example: API key re-resolution on 401 errors

func ExampleProviderRecoveryStrategy_basic

func ExampleProviderRecoveryStrategy_basic()

Example: Basic usage of ProviderRecoveryStrategy

func ExampleProviderRecoveryStrategy_customConfig

func ExampleProviderRecoveryStrategy_customConfig()

Example: Custom retry configuration

func ExampleProviderRecoveryStrategy_fromConfig

func ExampleProviderRecoveryStrategy_fromConfig()

Example: Configuration-based setup

func ExampleProviderRecoveryStrategy_integration

func ExampleProviderRecoveryStrategy_integration()

Example: Complete provider integration pattern

func ExampleProviderRecoveryStrategy_rateLimit

func ExampleProviderRecoveryStrategy_rateLimit()

Example: Rate limiting with Retry-After header

func ExampleProviderRecoveryStrategy_serverError

func ExampleProviderRecoveryStrategy_serverError()

Example: Server error with exponential backoff

func ExampleProviderRecoveryStrategy_timeoutIncrease

func ExampleProviderRecoveryStrategy_timeoutIncrease()

Example: Timeout increase on timeout errors

func ExampleProviderRecoveryStrategy_tokenReduction

func ExampleProviderRecoveryStrategy_tokenReduction()

Example: Token reduction on token limit errors

func Fallback

func Fallback(primary func() error, fallback func() error) error

Fallback executes a primary function and falls back to an alternative on error

func FallbackWithValue

func FallbackWithValue[T any](primary func() (T, error), fallbackValue T) (T, error)

FallbackWithValue executes a primary function and returns a fallback value on error

func Format

func Format(err error) string

Format formats an error for display

Example
err := NewConfigMissingError("api_key")
formatted := Format(err)
println(formatted)

func FormatChain

func FormatChain(err error) string

FormatChain formats the entire error chain

func FormatUser

func FormatUser(err error) string

FormatUser formats an error for end-user display (friendly message)

Example
err := NewAuthFailedError("openai", errors.New("invalid token"))
userMsg := FormatUser(err)
println(userMsg)

func FromJSON

func FromJSON(data []byte) error

FromJSON creates an error from a JSON representation

func Is

func Is(err, target error) bool

Is reports whether any error in err's chain matches target

func IsDebugMode

func IsDebugMode() bool

IsDebugMode returns whether debug mode is enabled

func IsRetryable

func IsRetryable(err error) bool

IsRetryable checks if an error is retryable

func Retry

func Retry(ctx context.Context, fn func() error, config *RetryConfig) error

Retry executes a function with retry logic

func RetryWithRecovery

func RetryWithRecovery(ctx context.Context, fn func() error, config *RetryConfig, recovery func(error) error) error

RetryWithRecovery executes a function with retry and recovery logic

func RootCause

func RootCause(err error) error

RootCause returns the root cause of an error

func ToJSON

func ToJSON(err error) ([]byte, error)

ToJSON converts an error to a JSON representation

func Unwrap

func Unwrap(err error) error

Unwrap returns the underlying error

func Wrap

func Wrap(err error, code ErrorCode, message string) error

Wrap wraps an existing error with additional context

Example
originalErr := fmt.Errorf("connection refused")
wrappedErr := Wrap(originalErr, ErrCodeDBConnection, "failed to connect to database")
fmt.Println(wrappedErr)
Output:

[DB_CONNECTION_FAILED] failed to connect to database: connection refused
Example (WithConfigError)
err := NewConfigInvalidError("timeout", "must be a positive integer")
fmt.Println(err.Code())
fmt.Println(err.Severity())
fmt.Println(err.IsRetryable())
Output:

CONFIG_INVALID
high
false

func Wrapf

func Wrapf(err error, code ErrorCode, format string, args ...interface{}) error

Wrapf wraps an error with a formatted message

Types

type AdvancedCircuitBreaker

type AdvancedCircuitBreaker struct {
	*CircuitBreaker
	// contains filtered or unexported fields
}

AdvancedCircuitBreaker extends the basic circuit breaker with error-specific behavior

func NewAdvancedCircuitBreaker

func NewAdvancedCircuitBreaker(maxFailures int, resetTimeout time.Duration) *AdvancedCircuitBreaker

NewAdvancedCircuitBreaker creates an advanced circuit breaker

func (*AdvancedCircuitBreaker) ExecuteWithErrorType

func (acb *AdvancedCircuitBreaker) ExecuteWithErrorType(fn func() error, errorType string) error

ExecuteWithErrorType executes a function with error-type-specific circuit breaking

func (*AdvancedCircuitBreaker) SetErrorThreshold

func (acb *AdvancedCircuitBreaker) SetErrorThreshold(errorType string, threshold int)

SetErrorThreshold sets a specific threshold for an error type

type AuthenticationError

type AuthenticationError struct {
	*BaseError
	Provider string
	UserID   string
	Resource string
}

AuthenticationError represents authentication and authorization errors

func NewAuthFailedError

func NewAuthFailedError(provider string, cause error) *AuthenticationError

NewAuthFailedError creates an error for general authentication failures

Example
originalErr := errors.New("connection timeout")
err := NewAuthFailedError("openai", originalErr)
println(err.Error())
println(err.UserMessage())

func NewAuthenticationError

func NewAuthenticationError(code ErrorCode, message string) *AuthenticationError

NewAuthenticationError creates a new authentication error

func NewExpiredTokenError

func NewExpiredTokenError(provider string) *AuthenticationError

NewExpiredTokenError creates an error for expired authentication tokens

func NewInvalidCredentialsError

func NewInvalidCredentialsError(provider string) *AuthenticationError

NewInvalidCredentialsError creates an error for invalid credentials

func NewInvalidTokenError

func NewInvalidTokenError(provider string) *AuthenticationError

NewInvalidTokenError creates an error for invalid authentication tokens

func NewPermissionDeniedError

func NewPermissionDeniedError(resource, action string) *AuthenticationError

NewPermissionDeniedError creates an error for permission/authorization failures

Example
err := NewPermissionDeniedError("/api/admin", "access")
println(err.Resource)
println(err.Severity())

func (*AuthenticationError) WithProvider

func (e *AuthenticationError) WithProvider(provider string) *AuthenticationError

WithProvider sets the authentication provider

func (*AuthenticationError) WithResource

func (e *AuthenticationError) WithResource(resource string) *AuthenticationError

WithResource sets the resource that was being accessed

func (*AuthenticationError) WithUserID

func (e *AuthenticationError) WithUserID(userID string) *AuthenticationError

WithUserID sets the user ID associated with the error

type BaseError

type BaseError struct {
	// contains filtered or unexported fields
}

BaseError is the foundation for all custom errors in the system

func (*BaseError) Code

func (e *BaseError) Code() ErrorCode

Code returns the error code

func (*BaseError) Error

func (e *BaseError) Error() string

Error implements the error interface

func (*BaseError) IsRetryable

func (e *BaseError) IsRetryable() bool

IsRetryable returns whether the error is retryable

func (*BaseError) Metadata

func (e *BaseError) Metadata() map[string]interface{}

Metadata returns error metadata

func (*BaseError) Severity

func (e *BaseError) Severity() Severity

Severity returns the error severity

func (*BaseError) Stack

func (e *BaseError) Stack() []StackFrame

Stack returns the stack trace

func (*BaseError) StackTrace

func (e *BaseError) StackTrace() string

StackTrace returns a formatted stack trace string

func (*BaseError) Unwrap

func (e *BaseError) Unwrap() error

Unwrap returns the underlying error

func (*BaseError) UserMessage

func (e *BaseError) UserMessage() string

UserMessage returns a user-friendly error message

func (*BaseError) WithMetadata

func (e *BaseError) WithMetadata(key string, value interface{}) *BaseError

WithMetadata adds metadata to the error

type CircuitBreaker

type CircuitBreaker struct {
	// contains filtered or unexported fields
}

CircuitBreaker implements the circuit breaker pattern for fault tolerance

func NewCircuitBreaker

func NewCircuitBreaker(maxFailures int, resetTimeout time.Duration) *CircuitBreaker

NewCircuitBreaker creates a new circuit breaker

func (*CircuitBreaker) Execute

func (cb *CircuitBreaker) Execute(fn func() error) error

Execute runs a function through the circuit breaker

func (*CircuitBreaker) GetState

func (cb *CircuitBreaker) GetState() CircuitState

GetState returns the current circuit state

func (*CircuitBreaker) Reset

func (cb *CircuitBreaker) Reset()

Reset manually resets the circuit breaker

type CircuitState

type CircuitState int

CircuitState represents the state of a circuit breaker

const (
	// StateClosed allows requests through
	StateClosed CircuitState = iota
	// StateOpen blocks requests
	StateOpen
	// StateHalfOpen allows limited requests to test recovery
	StateHalfOpen
)

type ConfigError

type ConfigError struct {
	*BaseError
	ConfigKey  string
	ConfigPath string
}

ConfigError represents configuration-related errors

func NewConfigError

func NewConfigError(code ErrorCode, message string, configKey string) *ConfigError

NewConfigError creates a new configuration error

func NewConfigInvalidError

func NewConfigInvalidError(configKey, reason string) *ConfigError

NewConfigInvalidError creates an error for invalid configuration

Example
err := NewConfigInvalidError("timeout", "must be a positive integer")
println(err.Error())
println(err.UserMessage())

func NewConfigMissingError

func NewConfigMissingError(configKey string) *ConfigError

NewConfigMissingError creates an error for missing configuration

Example
err := NewConfigMissingError("api_key")
println(err.ConfigKey)
println(err.Severity())

func NewConfigParseError

func NewConfigParseError(configPath string, cause error) *ConfigError

NewConfigParseError creates an error for configuration parsing failures

func NewConfigValidationError

func NewConfigValidationError(configKey, validationRule string) *ConfigError

NewConfigValidationError creates an error for configuration validation failures

func (*ConfigError) WithPath

func (e *ConfigError) WithPath(path string) *ConfigError

WithPath adds the configuration file path to the error

type DatabaseError

type DatabaseError struct {
	*BaseError
	Table      string
	Query      string
	Operation  string
	Constraint string
}

DatabaseError represents database-related errors

func NewDBConnectionError

func NewDBConnectionError(dbName string, cause error) *DatabaseError

NewDBConnectionError creates an error for database connection failures

Example
originalErr := errors.New("connection timeout")
err := NewDBConnectionError("postgres", originalErr)
println(err.Code())
println(err.IsRetryable())

func NewDBConstraintError

func NewDBConstraintError(table, constraint string, cause error) *DatabaseError

NewDBConstraintError creates an error for constraint violations

func NewDBDuplicateError

func NewDBDuplicateError(table, field, value string) *DatabaseError

NewDBDuplicateError creates an error for duplicate key violations

func NewDBNotFoundError

func NewDBNotFoundError(table, identifier string) *DatabaseError

NewDBNotFoundError creates an error for record not found

Example
err := NewDBNotFoundError("products", "sku=ABC123")
println(err.Error())
println(err.UserMessage())
println(err.Table)

func NewDBQueryError

func NewDBQueryError(operation, table string, cause error) *DatabaseError

NewDBQueryError creates an error for query execution failures

func NewDBTransactionError

func NewDBTransactionError(operation string, cause error) *DatabaseError

NewDBTransactionError creates an error for transaction failures

func NewDatabaseError

func NewDatabaseError(code ErrorCode, message string) *DatabaseError

NewDatabaseError creates a new database error

func (*DatabaseError) WithConstraint

func (e *DatabaseError) WithConstraint(constraint string) *DatabaseError

WithConstraint sets the constraint that was violated

func (*DatabaseError) WithOperation

func (e *DatabaseError) WithOperation(operation string) *DatabaseError

WithOperation sets the database operation

func (*DatabaseError) WithQuery

func (e *DatabaseError) WithQuery(query string) *DatabaseError

WithQuery sets the query that failed

func (*DatabaseError) WithTable

func (e *DatabaseError) WithTable(table string) *DatabaseError

WithTable sets the database table name

type ErrorCode

type ErrorCode string

ErrorCode represents a unique error code for categorization

const (
	// Configuration error codes
	ErrCodeConfigInvalid    ErrorCode = "CONFIG_INVALID"
	ErrCodeConfigMissing    ErrorCode = "CONFIG_MISSING"
	ErrCodeConfigParse      ErrorCode = "CONFIG_PARSE"
	ErrCodeConfigValidation ErrorCode = "CONFIG_VALIDATION"

	// Authentication error codes
	ErrCodeAuthFailed             ErrorCode = "AUTH_FAILED"
	ErrCodeAuthInvalidToken       ErrorCode = "AUTH_INVALID_TOKEN"
	ErrCodeAuthExpiredToken       ErrorCode = "AUTH_EXPIRED_TOKEN"
	ErrCodeAuthPermissionDenied   ErrorCode = "AUTH_PERMISSION_DENIED"
	ErrCodeAuthInvalidCredentials ErrorCode = "AUTH_INVALID_CREDENTIALS"

	// Provider error codes
	ErrCodeProviderUnavailable     ErrorCode = "PROVIDER_UNAVAILABLE"
	ErrCodeProviderTimeout         ErrorCode = "PROVIDER_TIMEOUT"
	ErrCodeProviderRateLimit       ErrorCode = "PROVIDER_RATE_LIMIT"
	ErrCodeProviderInvalidResponse ErrorCode = "PROVIDER_INVALID_RESPONSE"
	ErrCodeProviderNotFound        ErrorCode = "PROVIDER_NOT_FOUND"

	// Tool execution error codes
	ErrCodeToolNotFound         ErrorCode = "TOOL_NOT_FOUND"
	ErrCodeToolExecutionFailed  ErrorCode = "TOOL_EXECUTION_FAILED"
	ErrCodeToolTimeout          ErrorCode = "TOOL_TIMEOUT"
	ErrCodeToolInvalidInput     ErrorCode = "TOOL_INVALID_INPUT"
	ErrCodeToolPermissionDenied ErrorCode = "TOOL_PERMISSION_DENIED"

	// Database error codes
	ErrCodeDBConnection  ErrorCode = "DB_CONNECTION_FAILED"
	ErrCodeDBQuery       ErrorCode = "DB_QUERY_FAILED"
	ErrCodeDBNotFound    ErrorCode = "DB_NOT_FOUND"
	ErrCodeDBDuplicate   ErrorCode = "DB_DUPLICATE"
	ErrCodeDBConstraint  ErrorCode = "DB_CONSTRAINT_VIOLATION"
	ErrCodeDBTransaction ErrorCode = "DB_TRANSACTION_FAILED"

	// Security error codes
	ErrCodeSecurityViolation  ErrorCode = "SECURITY_VIOLATION"
	ErrCodeSecurityInvalidKey ErrorCode = "SECURITY_INVALID_KEY"
	ErrCodeSecurityEncryption ErrorCode = "SECURITY_ENCRYPTION_FAILED"
	ErrCodeSecurityDecryption ErrorCode = "SECURITY_DECRYPTION_FAILED"
)

func GetCode

func GetCode(err error) ErrorCode

GetCode extracts the error code from an error

type ErrorResponse

type ErrorResponse struct {
	Code      string                 `json:"code"`
	Message   string                 `json:"message"`
	UserMsg   string                 `json:"user_message,omitempty"`
	Severity  string                 `json:"severity"`
	Retryable bool                   `json:"retryable"`
	Metadata  map[string]interface{} `json:"metadata,omitempty"`
	Stack     []StackFrame           `json:"stack,omitempty"`
}

ErrorResponse represents a JSON error response

type ErrorSummary

type ErrorSummary struct {
	Code      string
	Message   string
	Severity  string
	Retryable bool
	HasCause  bool
	StackSize int
}

ErrorSummary provides a summary of an error for logging

func Summarize

func Summarize(err error) ErrorSummary

Summarize creates a summary of an error

type ExponentialBackoff

type ExponentialBackoff struct {
	InitialDelay time.Duration
	MaxDelay     time.Duration
	Multiplier   float64
	MaxRetries   int
}

ExponentialBackoff implements exponential backoff retry strategy

func NewExponentialBackoff

func NewExponentialBackoff() *ExponentialBackoff

NewExponentialBackoff creates a new exponential backoff strategy with sensible defaults

func (*ExponentialBackoff) GetDelay

func (e *ExponentialBackoff) GetDelay(attempt int) time.Duration

GetDelay calculates the exponential backoff delay

func (*ExponentialBackoff) MaxAttempts

func (e *ExponentialBackoff) MaxAttempts() int

MaxAttempts returns the maximum number of retry attempts

func (*ExponentialBackoff) ShouldRetry

func (e *ExponentialBackoff) ShouldRetry(err error, attempt int) bool

ShouldRetry determines if the error is retryable

type LinearBackoff

type LinearBackoff struct {
	Delay      time.Duration
	MaxRetries int
}

LinearBackoff implements linear backoff retry strategy

func NewLinearBackoff

func NewLinearBackoff(delay time.Duration, maxRetries int) *LinearBackoff

NewLinearBackoff creates a new linear backoff strategy

func (*LinearBackoff) GetDelay

func (l *LinearBackoff) GetDelay(attempt int) time.Duration

GetDelay returns a constant delay

func (*LinearBackoff) MaxAttempts

func (l *LinearBackoff) MaxAttempts() int

MaxAttempts returns the maximum number of retry attempts

func (*LinearBackoff) ShouldRetry

func (l *LinearBackoff) ShouldRetry(err error, attempt int) bool

ShouldRetry determines if the error is retryable

type ProviderError

type ProviderError struct {
	*BaseError
	ProviderName string
	Model        string
	RequestID    string
	StatusCode   int
	RetryAfter   *time.Duration
}

ProviderError represents errors related to external AI provider interactions

func NewProviderError

func NewProviderError(code ErrorCode, message string, providerName string) *ProviderError

NewProviderError creates a new provider error

func NewProviderInvalidResponseError

func NewProviderInvalidResponseError(providerName string, reason string, cause error) *ProviderError

NewProviderInvalidResponseError creates an error for invalid provider responses

func NewProviderNotFoundError

func NewProviderNotFoundError(providerName string) *ProviderError

NewProviderNotFoundError creates an error for provider not found

func NewProviderRateLimitError

func NewProviderRateLimitError(providerName string, retryAfter time.Duration) *ProviderError

NewProviderRateLimitError creates an error for rate limit exceeded

Example
retryAfter := 60 * time.Second
err := NewProviderRateLimitError("openai", retryAfter)
println(err.Error())
println(err.GetRetryDelay())
println(err.ShouldRetry())

func NewProviderTimeoutError

func NewProviderTimeoutError(providerName, model string, timeout time.Duration) *ProviderError

NewProviderTimeoutError creates an error for provider request timeouts

Example
err := NewProviderTimeoutError("anthropic", "claude-3", 30*time.Second)
println(err.ProviderName)
println(err.Model)
println(err.IsRetryable())

func NewProviderUnavailableError

func NewProviderUnavailableError(providerName string, cause error) *ProviderError

NewProviderUnavailableError creates an error for unavailable providers

func (*ProviderError) GetRetryDelay

func (e *ProviderError) GetRetryDelay() time.Duration

GetRetryDelay returns the suggested retry delay

func (*ProviderError) ShouldRetry

func (e *ProviderError) ShouldRetry() bool

ShouldRetry determines if the provider error should be retried

func (*ProviderError) WithModel

func (e *ProviderError) WithModel(model string) *ProviderError

WithModel sets the model name

func (*ProviderError) WithRequestID

func (e *ProviderError) WithRequestID(requestID string) *ProviderError

WithRequestID sets the request ID for tracking

func (*ProviderError) WithStatusCode

func (e *ProviderError) WithStatusCode(statusCode int) *ProviderError

WithStatusCode sets the HTTP status code

type ProviderRecoveryStrategy

type ProviderRecoveryStrategy struct {
	MaxRetries         int
	InitialBackoff     time.Duration
	MaxBackoff         time.Duration
	Multiplier         float64
	EnableJitter       bool
	OnAPIKeyResolution func(ctx context.Context) (string, error)
	OnTokenReduction   func(currentTokens int) int
	OnTimeoutIncrease  func(currentTimeout time.Duration) time.Duration
	Logger             func(message string)
}

ProviderRecoveryStrategy implements sophisticated recovery strategies for provider API failures

func NewProviderRecoveryStrategy

func NewProviderRecoveryStrategy() *ProviderRecoveryStrategy

NewProviderRecoveryStrategy creates a new provider recovery strategy with defaults

func (*ProviderRecoveryStrategy) AnalyzeError

func (p *ProviderRecoveryStrategy) AnalyzeError(ctx context.Context, err error, attempt int, statusCode int, retryAfterHeader string) RecoveryDecision

AnalyzeError analyzes an error and returns a recovery decision

func (*ProviderRecoveryStrategy) ExecuteWithRecovery

func (p *ProviderRecoveryStrategy) ExecuteWithRecovery(
	ctx context.Context,
	fn func(ctx context.Context) error,
	getStatusCode func() int,
	getRetryAfter func() string,
) error

ExecuteWithRecovery executes a function with sophisticated error recovery

type RecoveryAction

type RecoveryAction int

RecoveryAction represents an action to take for error recovery

const (
	// ActionRetry indicates a simple retry with backoff
	ActionRetry RecoveryAction = iota
	// ActionRetryWithBackoff indicates exponential backoff retry
	ActionRetryWithBackoff
	// ActionResolveAPIKey indicates re-resolution of API key before retry
	ActionResolveAPIKey
	// ActionReduceTokens indicates reducing max_tokens before retry
	ActionReduceTokens
	// ActionIncreaseTimeout indicates increasing timeout before retry
	ActionIncreaseTimeout
	// ActionCircuitBreak indicates circuit breaker activation
	ActionCircuitBreak
	// ActionFail indicates non-retryable error
	ActionFail
)

type RecoveryDecision

type RecoveryDecision struct {
	Action         RecoveryAction
	RetryAfter     time.Duration
	ShouldRetry    bool
	NewAPIKey      string
	TokenReduction int
	NewTimeout     time.Duration
	Message        string
}

RecoveryDecision contains the decision on how to handle an error

type RetryConfig

type RetryConfig struct {
	Strategy     RetryStrategy
	OnRetry      func(attempt int, err error)
	OnFinalError func(err error)
}

RetryConfig holds configuration for retry operations

func NewRetryConfig

func NewRetryConfig() *RetryConfig

NewRetryConfig creates a default retry configuration

type RetryStrategy

type RetryStrategy interface {
	// ShouldRetry determines if an error should trigger a retry
	ShouldRetry(err error, attempt int) bool

	// GetDelay calculates the delay before the next retry attempt
	GetDelay(attempt int) time.Duration

	// MaxAttempts returns the maximum number of retry attempts
	MaxAttempts() int
}

RetryStrategy defines the strategy for retrying failed operations

type SecurityError

type SecurityError struct {
	*BaseError
	Resource string
	Action   string
}

SecurityError represents security-related errors

func NewDecryptionError

func NewDecryptionError(reason string) *SecurityError

NewDecryptionError creates an error for decryption failures

func NewEncryptionError

func NewEncryptionError(reason string) *SecurityError

NewEncryptionError creates an error for encryption failures

func NewInvalidKeyError

func NewInvalidKeyError(keyType, reason string) *SecurityError

NewInvalidKeyError creates an error for invalid encryption/API keys

func NewSecurityError

func NewSecurityError(code ErrorCode, message string, resource string) *SecurityError

NewSecurityError creates a new security error

func NewSecurityViolationError

func NewSecurityViolationError(resource, action, reason string) *SecurityError

NewSecurityViolationError creates an error for security policy violations

func (*SecurityError) WithAction

func (e *SecurityError) WithAction(action string) *SecurityError

WithAction adds the action being attempted to the error

type Severity

type Severity string

Severity represents the severity level of an error

const (
	SeverityLow      Severity = "low"
	SeverityMedium   Severity = "medium"
	SeverityHigh     Severity = "high"
	SeverityCritical Severity = "critical"
)

func GetSeverity

func GetSeverity(err error) Severity

GetSeverity extracts the severity from an error

type StackFrame

type StackFrame struct {
	File     string
	Line     int
	Function string
}

StackFrame represents a single frame in the stack trace

type ToolExecutionError

type ToolExecutionError struct {
	*BaseError
	ToolName   string
	ToolPath   string
	Parameters map[string]interface{}
	ExitCode   int
	Output     string
}

ToolExecutionError represents errors during tool execution

func NewToolExecutionError

func NewToolExecutionError(code ErrorCode, message string, toolName string) *ToolExecutionError

NewToolExecutionError creates a new tool execution error

func NewToolExecutionFailedError

func NewToolExecutionFailedError(toolName string, exitCode int, output string, cause error) *ToolExecutionError

NewToolExecutionFailedError creates an error for failed tool executions

Example
originalErr := errors.New("exit status 1")
err := NewToolExecutionFailedError("git", 1, "fatal: not a git repository", originalErr)
println(err.Error())
println(err.ExitCode)
println(err.GetOutput(100))

func NewToolInvalidInputError

func NewToolInvalidInputError(toolName, paramName, reason string) *ToolExecutionError

NewToolInvalidInputError creates an error for invalid tool input

func NewToolNotFoundError

func NewToolNotFoundError(toolName string) *ToolExecutionError

NewToolNotFoundError creates an error for tools that cannot be found

func NewToolPermissionDeniedError

func NewToolPermissionDeniedError(toolName, resource string) *ToolExecutionError

NewToolPermissionDeniedError creates an error for permission-related tool failures

func NewToolTimeoutError

func NewToolTimeoutError(toolName string, timeout time.Duration) *ToolExecutionError

NewToolTimeoutError creates an error for tool execution timeouts

Example
err := NewToolTimeoutError("terraform", 30*time.Second)
println(err.ToolName)
println(err.IsRetryable())

func (*ToolExecutionError) GetOutput

func (e *ToolExecutionError) GetOutput(maxLength int) string

GetOutput returns the tool output, truncated if necessary

func (*ToolExecutionError) WithExitCode

func (e *ToolExecutionError) WithExitCode(exitCode int) *ToolExecutionError

WithExitCode sets the exit code

func (*ToolExecutionError) WithOutput

func (e *ToolExecutionError) WithOutput(output string) *ToolExecutionError

WithOutput sets the tool output

func (*ToolExecutionError) WithParameter

func (e *ToolExecutionError) WithParameter(name string, value interface{}) *ToolExecutionError

WithParameter adds a parameter to the error context

func (*ToolExecutionError) WithPath

func (e *ToolExecutionError) WithPath(path string) *ToolExecutionError

WithPath sets the tool path

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL