Errors
The Go Pip SDK provides a comprehensive error handling system with structured error types, helpful suggestions, and context-aware error messages.
Error Types
ErrorType
type ErrorType string
Enumeration of all possible error types in the SDK.
Constants:
const (
ErrorTypePipNotInstalled ErrorType = "pip_not_installed"
ErrorTypePythonNotFound ErrorType = "python_not_found"
ErrorTypePackageNotFound ErrorType = "package_not_found"
ErrorTypeVenvNotFound ErrorType = "venv_not_found"
ErrorTypeVenvAlreadyExists ErrorType = "venv_already_exists"
ErrorTypeInvalidPackageSpec ErrorType = "invalid_package_spec"
ErrorTypeCommandFailed ErrorType = "command_failed"
ErrorTypePermissionDenied ErrorType = "permission_denied"
ErrorTypeNetworkError ErrorType = "network_error"
ErrorTypeUnsupportedOS ErrorType = "unsupported_os"
ErrorTypeFileNotFound ErrorType = "file_not_found"
ErrorTypeInvalidPath ErrorType = "invalid_path"
ErrorTypeFeatureDisabled ErrorType = "feature_disabled"
ErrorTypeTimeout ErrorType = "timeout"
ErrorTypeInvalidConfig ErrorType = "invalid_config"
)
Core Error Types
PipErrorDetails
type PipErrorDetails struct {
Type ErrorType // Error type classification
Message string // Human-readable error message
Command string // Command that failed (if applicable)
Output string // Command output (if applicable)
ExitCode int // Command exit code (if applicable)
Suggestions []string // Helpful suggestions for resolution
Context map[string]string // Additional context information
Cause error // Underlying cause (if any)
}
The main error type that implements the standard Go error
interface with additional context.
Methods:
Error
func (e *PipErrorDetails) Error() string
Returns a formatted error message including type, message, command, and suggestions.
Unwrap
func (e *PipErrorDetails) Unwrap() error
Returns the underlying cause error for error chain unwrapping.
Is
func (e *PipErrorDetails) Is(target error) bool
Checks if the error matches a target error type.
WithSuggestion
func (e *PipErrorDetails) WithSuggestion(suggestion string) *PipErrorDetails
Adds a suggestion to the error and returns the error for chaining.
Example:
err := pip.NewPipError(pip.ErrorTypePackageNotFound, "package 'nonexistent' not found").
WithSuggestion("Check the package name spelling").
WithSuggestion("Search for the package on PyPI")
fmt.Println(err.Error())
// Output: [package_not_found] package 'nonexistent' not found | Suggestions: Check the package name spelling, Search for the package on PyPI
Constructor Functions
NewPipError
func NewPipError(errorType ErrorType, message string) *PipErrorDetails
Creates a new pip error with the specified type and message.
Parameters:
errorType
(ErrorType): The error type classification.message
(string): Human-readable error message.
Returns:
*PipErrorDetails
: New error instance.
NewCommandError
func NewCommandError(command string, output string, exitCode int, cause error) *PipErrorDetails
Creates a new command execution error with automatic suggestion generation.
Parameters:
command
(string): The command that failed.output
(string): Command output.exitCode
(int): Command exit code.cause
(error): Underlying cause error.
Returns:
*PipErrorDetails
: New command error instance.
WrapError
func WrapError(err error, errorType ErrorType, message string) *PipErrorDetails
Wraps a generic error into a PipErrorDetails with additional context.
Parameters:
err
(error): Original error to wrap.errorType
(ErrorType): Error type classification.message
(string): Additional context message.
Returns:
*PipErrorDetails
: Wrapped error.
Predefined Errors
The SDK provides predefined error instances for common scenarios:
var (
ErrPipNotInstalled = NewPipError(ErrorTypePipNotInstalled, "pip is not installed").
WithSuggestion("Install pip using your system package manager or download get-pip.py")
ErrPythonNotFound = NewPipError(ErrorTypePythonNotFound, "Python interpreter not found").
WithSuggestion("Install Python from https://python.org or use your system package manager")
ErrPackageNotFound = NewPipError(ErrorTypePackageNotFound, "package not found").
WithSuggestion("Check the package name spelling and availability on PyPI")
ErrVenvNotFound = NewPipError(ErrorTypeVenvNotFound, "virtual environment not found").
WithSuggestion("Create a virtual environment first using CreateVenv()")
ErrVenvAlreadyExists = NewPipError(ErrorTypeVenvAlreadyExists, "virtual environment already exists").
WithSuggestion("Use a different path or remove the existing virtual environment")
ErrInvalidPackageSpec = NewPipError(ErrorTypeInvalidPackageSpec, "invalid package specification").
WithSuggestion("Ensure package name is not empty and version constraints are valid")
ErrPermissionDenied = NewPipError(ErrorTypePermissionDenied, "permission denied").
WithSuggestion("Run with elevated privileges or check file/directory permissions")
ErrNetworkError = NewPipError(ErrorTypeNetworkError, "network error").
WithSuggestion("Check your internet connection and proxy settings")
ErrUnsupportedOS = NewPipError(ErrorTypeUnsupportedOS, "unsupported operating system").
WithSuggestion("This operation is not supported on your operating system")
ErrFeatureDisabled = NewPipError(ErrorTypeFeatureDisabled, "feature is disabled").
WithSuggestion("This feature has been disabled or is not available")
)
Utility Functions
IsErrorType
func IsErrorType(err error, errorType ErrorType) bool
Checks if an error is of a specific type.
Parameters:
err
(error): Error to check.errorType
(ErrorType): Expected error type.
Returns:
bool
:true
if the error matches the specified type.
Example:
if err := manager.InstallPackage(pkg); err != nil {
if pip.IsErrorType(err, pip.ErrorTypePackageNotFound) {
fmt.Println("Package not found - check the name")
return nil // Handle gracefully
}
return err // Propagate other errors
}
GetErrorType
func GetErrorType(err error) ErrorType
Returns the error type if it's a PipErrorDetails, otherwise returns empty string.
Parameters:
err
(error): Error to examine.
Returns:
ErrorType
: Error type or empty string.
Example:
if err := manager.CreateVenv(path); err != nil {
switch pip.GetErrorType(err) {
case pip.ErrorTypeVenvAlreadyExists:
fmt.Println("Virtual environment already exists")
case pip.ErrorTypePermissionDenied:
fmt.Println("Permission denied")
default:
fmt.Printf("Unexpected error: %v\n", err)
}
}
Error Handler
ErrorHandler
type ErrorHandler struct {
logger *Logger
}
Provides centralized error handling and logging.
NewErrorHandler
func NewErrorHandler(logger *Logger) *ErrorHandler
Creates a new error handler with the specified logger.
Handle
func (eh *ErrorHandler) Handle(err error, context string) error
Processes an error and logs it appropriately based on the error type.
Parameters:
err
(error): Error to handle.context
(string): Context description for logging.
Returns:
error
: Processed error (may be wrapped if it wasn't already a PipErrorDetails).
Example:
logger, _ := pip.NewLogger(pip.DefaultLoggerConfig())
handler := pip.NewErrorHandler(logger)
if err := manager.InstallPackage(pkg); err != nil {
return handler.Handle(err, "package installation")
}
Error Handling Patterns
Basic Error Checking
if err := manager.InstallPackage(pkg); err != nil {
if pip.IsErrorType(err, pip.ErrorTypePackageNotFound) {
// Handle package not found specifically
fmt.Printf("Package %s not found\n", pkg.Name)
return nil
}
// Handle other errors
return fmt.Errorf("installation failed: %w", err)
}
Comprehensive Error Handling
func handlePipError(err error) {
if err == nil {
return
}
pipErr, ok := err.(*pip.PipErrorDetails)
if !ok {
fmt.Printf("Unexpected error: %v\n", err)
return
}
fmt.Printf("Error Type: %s\n", pipErr.Type)
fmt.Printf("Message: %s\n", pipErr.Message)
if pipErr.Command != "" {
fmt.Printf("Failed Command: %s\n", pipErr.Command)
}
if pipErr.ExitCode != 0 {
fmt.Printf("Exit Code: %d\n", pipErr.ExitCode)
}
if len(pipErr.Suggestions) > 0 {
fmt.Println("Suggestions:")
for _, suggestion := range pipErr.Suggestions {
fmt.Printf(" - %s\n", suggestion)
}
}
if pipErr.Cause != nil {
fmt.Printf("Underlying cause: %v\n", pipErr.Cause)
}
}
Error Recovery
func installWithRetry(manager *pip.Manager, pkg *pip.PackageSpec, maxRetries int) error {
var lastErr error
for i := 0; i < maxRetries; i++ {
err := manager.InstallPackage(pkg)
if err == nil {
return nil // Success
}
lastErr = err
// Check if error is recoverable
if pip.IsErrorType(err, pip.ErrorTypeNetworkError) {
fmt.Printf("Network error, retrying... (%d/%d)\n", i+1, maxRetries)
time.Sleep(time.Duration(i+1) * time.Second)
continue
}
// Non-recoverable error
break
}
return lastErr
}
Graceful Degradation
func installOptionalPackage(manager *pip.Manager, pkg *pip.PackageSpec) {
if err := manager.InstallPackage(pkg); err != nil {
switch pip.GetErrorType(err) {
case pip.ErrorTypePackageNotFound:
fmt.Printf("Optional package %s not available, skipping\n", pkg.Name)
case pip.ErrorTypePermissionDenied:
fmt.Printf("Permission denied for %s, skipping\n", pkg.Name)
default:
fmt.Printf("Failed to install optional package %s: %v\n", pkg.Name, err)
}
// Continue execution without failing
}
}
Best Practices
Always check error types for specific handling:
goif err != nil { if pip.IsErrorType(err, pip.ErrorTypePackageNotFound) { // Specific handling for package not found } else { // Generic error handling } }
Use error wrapping for context:
goif err := manager.InstallPackage(pkg); err != nil { return fmt.Errorf("failed to install %s: %w", pkg.Name, err) }
Log errors with appropriate levels:
goif err := manager.InstallPackage(pkg); err != nil { if pip.IsErrorType(err, pip.ErrorTypeNetworkError) { logger.Warn("Network issue during installation: %v", err) } else { logger.Error("Installation failed: %v", err) } }
Provide helpful error messages to users:
goif err := manager.CreateVenv(path); err != nil { if pip.IsErrorType(err, pip.ErrorTypePermissionDenied) { return fmt.Errorf("cannot create virtual environment: permission denied. Try running with elevated privileges or choose a different location") } return err }
Error Context
Errors can include additional context information:
err := pip.NewPipError(pip.ErrorTypePackageNotFound, "package not found")
if pipErr, ok := err.(*pip.PipErrorDetails); ok {
pipErr.Context["package_name"] = "nonexistent-package"
pipErr.Context["index_url"] = "https://pypi.org/simple/"
pipErr.Context["python_version"] = "3.9"
}
This context can be used for debugging, logging, or providing more detailed error information to users.