Skip to content

Errors

The CPE library provides a comprehensive error handling system with structured error types for different failure scenarios.

Error Types

ErrorType

go
type ErrorType int

const (
    ErrorTypeParsingFailed    ErrorType = iota // Parsing operation failed
    ErrorTypeInvalidFormat                     // Invalid format detected
    ErrorTypeInvalidPart                       // Invalid part value
    ErrorTypeInvalidAttribute                  // Invalid attribute value
    ErrorTypeNotFound                          // Resource not found
    ErrorTypeOperationFailed                   // General operation failure
)

Enumeration of different error types that can occur in the library.

CPEError

go
type CPEError struct {
    Type      ErrorType // Error type classification
    Message   string    // Human-readable error message
    CPEString string    // Related CPE string (if applicable)
    Err       error     // Underlying error (if any)
}

The main error type used throughout the library, providing structured error information.

Methods

Error
go
func (e *CPEError) Error() string

Implements the error interface, returning a formatted error message.

Returns:

  • string - Formatted error message

Example:

go
err := cpe.NewInvalidFormatError("invalid:cpe:format")
fmt.Printf("Error: %s\n", err.Error())
// Output: invalid CPE format: invalid:cpe:format
Unwrap
go
func (e *CPEError) Unwrap() error

Returns the underlying error for error chain unwrapping.

Returns:

  • error - Underlying error or nil

Example:

go
originalErr := errors.New("underlying issue")
cpeErr := cpe.NewOperationFailedError("parse", originalErr)

unwrapped := cpeErr.Unwrap()
fmt.Printf("Underlying error: %v\n", unwrapped)

Error Constructors

NewParsingError

go
func NewParsingError(cpeString string, err error) *CPEError

Creates a parsing error for when CPE string parsing fails.

Parameters:

  • cpeString - The CPE string that failed to parse
  • err - Underlying parsing error

Returns:

  • *CPEError - Parsing error

Example:

go
err := cpe.NewParsingError("invalid:format", errors.New("malformed string"))
fmt.Printf("Parsing error: %v\n", err)

NewInvalidFormatError

go
func NewInvalidFormatError(cpeString string) *CPEError

Creates an error for invalid CPE format.

Parameters:

  • cpeString - The invalid CPE string

Returns:

  • *CPEError - Invalid format error

Example:

go
err := cpe.NewInvalidFormatError("not:a:valid:cpe")
fmt.Printf("Format error: %v\n", err)

NewInvalidPartError

go
func NewInvalidPartError(part string) *CPEError

Creates an error for invalid CPE part values.

Parameters:

  • part - The invalid part value

Returns:

  • *CPEError - Invalid part error

Example:

go
err := cpe.NewInvalidPartError("x") // Valid parts are "a", "h", "o"
fmt.Printf("Part error: %v\n", err)

NewInvalidAttributeError

go
func NewInvalidAttributeError(attribute, value string) *CPEError

Creates an error for invalid attribute values.

Parameters:

  • attribute - Name of the invalid attribute
  • value - The invalid value

Returns:

  • *CPEError - Invalid attribute error

Example:

go
err := cpe.NewInvalidAttributeError("vendor", "invalid\x00vendor")
fmt.Printf("Attribute error: %v\n", err)

NewNotFoundError

go
func NewNotFoundError(what string) *CPEError

Creates an error for when a resource is not found.

Parameters:

  • what - Description of what was not found

Returns:

  • *CPEError - Not found error

Example:

go
err := cpe.NewNotFoundError("CPE dictionary")
fmt.Printf("Not found error: %v\n", err)

NewOperationFailedError

go
func NewOperationFailedError(operation string, err error) *CPEError

Creates an error for when an operation fails.

Parameters:

  • operation - Name of the failed operation
  • err - Underlying error

Returns:

  • *CPEError - Operation failed error

Example:

go
err := cpe.NewOperationFailedError("download", errors.New("network timeout"))
fmt.Printf("Operation error: %v\n", err)

Error Checking Functions

IsParsingError

go
func IsParsingError(err error) bool

Checks if an error is a parsing error.

Parameters:

  • err - Error to check

Returns:

  • bool - true if it's a parsing error

Example:

go
_, err := cpe.ParseCpe23("invalid:format")
if cpe.IsParsingError(err) {
    fmt.Println("This is a parsing error")
}

IsInvalidFormatError

go
func IsInvalidFormatError(err error) bool

Checks if an error is an invalid format error.

Parameters:

  • err - Error to check

Returns:

  • bool - true if it's an invalid format error

IsInvalidPartError

go
func IsInvalidPartError(err error) bool

Checks if an error is an invalid part error.

Parameters:

  • err - Error to check

Returns:

  • bool - true if it's an invalid part error

IsInvalidAttributeError

go
func IsInvalidAttributeError(err error) bool

Checks if an error is an invalid attribute error.

Parameters:

  • err - Error to check

Returns:

  • bool - true if it's an invalid attribute error

IsNotFoundError

go
func IsNotFoundError(err error) bool

Checks if an error is a not found error.

Parameters:

  • err - Error to check

Returns:

  • bool - true if it's a not found error

IsOperationFailedError

go
func IsOperationFailedError(err error) bool

Checks if an error is an operation failed error.

Parameters:

  • err - Error to check

Returns:

  • bool - true if it's an operation failed error

Storage Errors

The library also defines standard storage errors:

go
var (
    ErrNotFound              = errors.New("record not found")
    ErrDuplicate             = errors.New("duplicate record")
    ErrInvalidData           = errors.New("invalid data")
    ErrStorageDisconnected   = errors.New("storage is disconnected")
)

These can be used with errors.Is() for checking:

Example:

go
cpe, err := storage.RetrieveCPE("non-existent")
if errors.Is(err, cpe.ErrNotFound) {
    fmt.Println("CPE not found in storage")
}

Error Handling Patterns

Basic Error Handling

go
// Parse CPE and handle errors
cpeObj, err := cpe.ParseCpe23("invalid:format")
if err != nil {
    if cpe.IsInvalidFormatError(err) {
        fmt.Println("Invalid CPE format provided")
    } else {
        fmt.Printf("Other parsing error: %v\n", err)
    }
    return
}

Detailed Error Information

go
// Get detailed error information
_, err := cpe.ParseCpe23("cpe:2.3:x:vendor:product:1.0:*:*:*:*:*:*:*")
if err != nil {
    if cpeErr, ok := err.(*cpe.CPEError); ok {
        fmt.Printf("Error type: %d\n", cpeErr.Type)
        fmt.Printf("Message: %s\n", cpeErr.Message)
        fmt.Printf("CPE string: %s\n", cpeErr.CPEString)
        
        if cpeErr.Err != nil {
            fmt.Printf("Underlying error: %v\n", cpeErr.Err)
        }
    }
}

Error Chain Unwrapping

go
// Handle error chains
err := someComplexOperation()
if err != nil {
    // Check for specific error types in the chain
    var cpeErr *cpe.CPEError
    if errors.As(err, &cpeErr) {
        fmt.Printf("CPE error found: %s\n", cpeErr.Message)
    }
    
    // Check for storage errors
    if errors.Is(err, cpe.ErrNotFound) {
        fmt.Println("Resource not found")
    }
}

Comprehensive Error Handling

go
func handleCPEOperation(cpeString string) {
    cpeObj, err := cpe.ParseCpe23(cpeString)
    if err != nil {
        switch {
        case cpe.IsInvalidFormatError(err):
            fmt.Printf("Invalid format: %s\n", cpeString)
        case cpe.IsInvalidPartError(err):
            fmt.Printf("Invalid part in: %s\n", cpeString)
        case cpe.IsParsingError(err):
            fmt.Printf("General parsing error: %v\n", err)
        default:
            fmt.Printf("Unexpected error: %v\n", err)
        }
        return
    }
    
    // Use the parsed CPE
    fmt.Printf("Successfully parsed: %s\n", cpeObj.GetURI())
}

Complete Example

go
package main

import (
    "errors"
    "fmt"
    "github.com/scagogogo/cpe"
)

func main() {
    // Test different error scenarios
    fmt.Println("=== Error Handling Examples ===")
    
    // Invalid format error
    fmt.Println("\n1. Invalid Format Error:")
    _, err := cpe.ParseCpe23("invalid:format")
    if err != nil {
        if cpe.IsInvalidFormatError(err) {
            fmt.Printf("✓ Detected invalid format error: %v\n", err)
        }
    }
    
    // Invalid part error
    fmt.Println("\n2. Invalid Part Error:")
    _, err = cpe.ParseCpe23("cpe:2.3:x:vendor:product:1.0:*:*:*:*:*:*:*")
    if err != nil {
        if cpe.IsInvalidPartError(err) {
            fmt.Printf("✓ Detected invalid part error: %v\n", err)
        }
    }
    
    // Storage error simulation
    fmt.Println("\n3. Storage Error:")
    storage := cpe.NewMemoryStorage()
    storage.Initialize()
    
    _, err = storage.RetrieveCPE("non-existent-cpe")
    if err != nil {
        if errors.Is(err, cpe.ErrNotFound) {
            fmt.Printf("✓ Detected not found error: %v\n", err)
        }
    }
    
    // Detailed error information
    fmt.Println("\n4. Detailed Error Information:")
    _, err = cpe.ParseCpe23("cpe:2.3:invalid:vendor:product:1.0:*:*:*:*:*:*:*")
    if err != nil {
        if cpeErr, ok := err.(*cpe.CPEError); ok {
            fmt.Printf("Error Type: %d\n", cpeErr.Type)
            fmt.Printf("Message: %s\n", cpeErr.Message)
            fmt.Printf("CPE String: %s\n", cpeErr.CPEString)
        }
    }
    
    // Error type checking
    fmt.Println("\n5. Error Type Checking:")
    testCases := []struct {
        input       string
        description string
    }{
        {"invalid", "completely invalid"},
        {"cpe:2.3:x:vendor:product:1.0:*:*:*:*:*:*:*", "invalid part"},
        {"cpe:2.3:a:vendor:product", "too few components"},
    }
    
    for _, tc := range testCases {
        _, err := cpe.ParseCpe23(tc.input)
        if err != nil {
            fmt.Printf("Input: %s (%s)\n", tc.input, tc.description)
            
            switch {
            case cpe.IsInvalidFormatError(err):
                fmt.Println("  → Invalid format error")
            case cpe.IsInvalidPartError(err):
                fmt.Println("  → Invalid part error")
            case cpe.IsParsingError(err):
                fmt.Println("  → General parsing error")
            default:
                fmt.Println("  → Other error type")
            }
        }
    }
    
    // Successful operation
    fmt.Println("\n6. Successful Operation:")
    cpeObj, err := cpe.ParseCpe23("cpe:2.3:a:microsoft:windows:10:*:*:*:*:*:*:*")
    if err != nil {
        fmt.Printf("Unexpected error: %v\n", err)
    } else {
        fmt.Printf("✓ Successfully parsed: %s\n", cpeObj.GetURI())
    }
}

Released under the MIT License.