Documentation
¶
Overview ¶
Package errors provides structured error types for better observability and programmatic error handling across the application.
Overview ¶
This package implements a structured error system with error codes for programmatic handling, human-readable messages, cause chaining, and optional context for debugging. It supports the standard errors.Is and errors.As functions through the Unwrap interface.
Error Codes ¶
Predefined error codes align with the API error contract:
- ErrCodeNotFound: Resource not found (HTTP 404)
- ErrCodeUnauthorized: Authentication/authorization failure (HTTP 401/403)
- ErrCodeTimeout: Operation timeout (HTTP 504)
- ErrCodeInternal: Internal server error (HTTP 500)
- ErrCodeInvalidRequest: Malformed or invalid input (HTTP 400)
- ErrCodeRateLimitExceeded: Rate limit exceeded (HTTP 429)
- ErrCodeMethodNotAllowed: HTTP method not allowed (HTTP 405)
- ErrCodeUnavailable: Service temporarily unavailable (HTTP 503)
- ErrCodeConflict: Resource state conflict, e.g., already exists or version mismatch (HTTP 409). Distinct from ErrCodeInvalidRequest because the request itself is well-formed.
Usage ¶
Create a simple error:
err := errors.New(errors.ErrCodeNotFound, "GPU not found")
Wrap an existing error:
err := errors.Wrap(errors.ErrCodeInternal, "collection failed", originalErr)
Wrap with additional context:
err := errors.WrapWithContext(
errors.ErrCodeTimeout,
"failed to collect GPU metrics",
ctx.Err(),
map[string]any{
"command": "nvidia-smi",
"node": nodeName,
"timeout": "10s",
},
)
Error Handling ¶
The StructuredError type implements the standard error interface and supports error unwrapping:
var structErr *errors.StructuredError
if errors.As(err, &structErr) {
log.Printf("Error code: %s, Message: %s", structErr.Code, structErr.Message)
if structErr.Context != nil {
log.Printf("Context: %v", structErr.Context)
}
}
Code-Based Matching with errors.Is ¶
StructuredError.Is reports a match when the target is also a *StructuredError with the same Code. This enables idiomatic errors.Is checks without reaching for errors.As + manual code comparison:
if errors.Is(err, errors.New(errors.ErrCodeNotFound, "")) {
// err (or any error in its Unwrap chain) carries
// ErrCodeNotFound.
}
Message and Cause are not compared; for cause-chain matching, rely on Unwrap as usual.
Thread Safety ¶
All functions in this package are thread-safe and can be called concurrently. Note: StructuredError.Context is a mutable map; if consumers mutate it post-construction, that mutation is the caller's responsibility.
Index ¶
- Constants
- func ExitCodeFromError(err error) int
- func IsNetworkError(err error) bool
- func PropagateOrWrap(err error, fallbackCode ErrorCode, message string) error
- type ErrorCode
- type StructuredError
- func New(code ErrorCode, message string) *StructuredError
- func NewWithContext(code ErrorCode, message string, context map[string]any) *StructuredError
- func Wrap(code ErrorCode, message string, cause error) *StructuredError
- func WrapWithContext(code ErrorCode, message string, cause error, context map[string]any) *StructuredError
Constants ¶
const ( // ExitSuccess indicates successful execution. ExitSuccess = 0 // ExitError is the generic error code for unclassified failures. ExitError = 1 // ExitInvalidInput indicates malformed input, validation failure, or bad arguments. // Maps to: ErrCodeInvalidRequest, ErrCodeMethodNotAllowed ExitInvalidInput = 2 // ExitNotFound indicates a requested resource was not found. // Maps to: ErrCodeNotFound ExitNotFound = 3 // Maps to: ErrCodeUnauthorized ExitUnauthorized = 4 // ExitTimeout indicates an operation exceeded its time limit. // Maps to: ErrCodeTimeout ExitTimeout = 5 // Maps to: ErrCodeUnavailable ExitUnavailable = 6 // ExitRateLimited indicates the client exceeded a rate limit. // Maps to: ErrCodeRateLimitExceeded ExitRateLimited = 7 // ExitInternal indicates an internal error (reserved for unexpected failures). // Maps to: ErrCodeInternal ExitInternal = 8 )
Exit codes for CLI commands, following Unix conventions. These codes enable predictable scripting and automation.
Ranges:
- 0: Success
- 1: Generic error (catch-all)
- 2-63: Application-specific errors
Variables ¶
This section is empty.
Functions ¶
func ExitCodeFromError ¶
ExitCodeFromError extracts an appropriate exit code from an error. It checks for StructuredError to determine the specific exit code, falling back to ExitError (1) for unstructured errors.
func IsNetworkError ¶ added in v0.8.4
IsNetworkError reports whether err indicates a network-level connectivity problem (DNS resolution, TCP dial, TLS handshake, etc.).
It does NOT match context.DeadlineExceeded or context.Canceled — those represent application-level timeouts, not network failures.
func PropagateOrWrap ¶ added in v0.13.0
PropagateOrWrap returns err as-is when it already carries a *StructuredError in its Unwrap chain (preserving the inner Code), otherwise wraps it with the supplied fallback code and message. Use this when the called function may return a coded error you want to preserve, but its non-coded errors still need classification at this layer.
Types ¶
type ErrorCode ¶
type ErrorCode string
ErrorCode represents a structured error classification.
const ( // ErrCodeNotFound indicates a requested resource was not found. ErrCodeNotFound ErrorCode = "NOT_FOUND" ErrCodeUnauthorized ErrorCode = "UNAUTHORIZED" // ErrCodeTimeout indicates an operation exceeded its time limit. ErrCodeTimeout ErrorCode = "TIMEOUT" // ErrCodeInternal indicates an internal system error. ErrCodeInternal ErrorCode = "INTERNAL" // ErrCodeInvalidRequest indicates malformed or invalid input. ErrCodeInvalidRequest ErrorCode = "INVALID_REQUEST" // ErrCodeRateLimitExceeded indicates the client exceeded an enforced request limit. ErrCodeRateLimitExceeded ErrorCode = "RATE_LIMIT_EXCEEDED" // ErrCodeMethodNotAllowed indicates the HTTP method is not allowed for the resource. ErrCodeMethodNotAllowed ErrorCode = "METHOD_NOT_ALLOWED" // // Note: this value is aligned with the public API error contract. ErrCodeUnavailable ErrorCode = "SERVICE_UNAVAILABLE" // ErrCodeConflict indicates a resource state conflict (e.g., already exists, // version mismatch). Distinct from ErrCodeInvalidRequest because the request // itself is well-formed; the conflict is with current resource state. ErrCodeConflict ErrorCode = "CONFLICT" )
type StructuredError ¶
StructuredError provides structured error information for better observability. It includes an error code for programmatic handling, a human-readable message, the underlying cause, and optional context for debugging.
func New ¶
func New(code ErrorCode, message string) *StructuredError
New creates a new StructuredError with the given code and message.
func NewWithContext ¶
func NewWithContext(code ErrorCode, message string, context map[string]any) *StructuredError
NewWithContext creates a new StructuredError with context information.
func Wrap ¶
func Wrap(code ErrorCode, message string, cause error) *StructuredError
Wrap wraps an existing error with additional context.
func WrapWithContext ¶
func WrapWithContext(code ErrorCode, message string, cause error, context map[string]any) *StructuredError
WrapWithContext wraps an error with additional context information.
func (*StructuredError) Error ¶
func (e *StructuredError) Error() string
Error implements the error interface.
func (*StructuredError) Is ¶ added in v0.13.0
func (e *StructuredError) Is(target error) bool
Is reports whether target is a *StructuredError with the same Code, enabling idiomatic code-based matching via errors.Is. The Message and Cause are not compared; callers wanting cause-chain matching should rely on Unwrap.
func (*StructuredError) Unwrap ¶
func (e *StructuredError) Unwrap() error
Unwrap returns the underlying cause for errors.Is and errors.As support.