errors
Last updated
Last updated
The errors package provides a centralized error handling library for Go applications. It standardizes error codes, messages, and HTTP status codes across services, making error management consistent and efficient.
Standardized Error Codes: Uses a consistent error code format (xyyzzz
) across services.
Service Prefixes: Allows setting a service-specific prefix for error codes.
Domain Errors: Provides a DomainError
interface for custom errors.
Base Error Embedding: Encourages embedding BaseError
for consistency.
Utilities: Includes helper functions for wrapping, unwrapping, and extracting errors.
Category Validation: Validates that error codes align with predefined categories.
Before using the error handling library, set the service-specific prefix. This helps in identifying which service an error originated from.
Define custom errors by embedding *errors.BaseError
in your error type. This ensures that custom errors conform to the DomainError
interface and can be properly handled by the error utilities.
To avoid handling errors every time you create a custom error, you can design your constructors to handle any internal errors themselves. This way, your error creation functions can have a simpler signature, returning only the custom error. You can handle internal errors by:
Panicking
If errors.NewBaseError
returns an error
, it likely indicates a misconfiguration or coding error (e.g., invalid error code). In such cases, it's acceptable to panic during development to catch the issue early.
Returning an Error Interface ✅
If you want the option to handle the error in the calling function, you can modify your constructor to return an error
interface.
This allows proper handling of ErrBaseErrorCreationFailed
, which is returned when NewBaseError fails due to invalid error codes or categories.
Using init()
to Initialize Predefined Errors
You can simplify handling predefined errors by initializing them at the package level. This approach removes the need to handle errors every time you use these predefined errors. If NewBaseError
fails during initialization (e.g., due to a misconfiguration), log.Fatal
will immediately halt the program and output the error. This way, issues are caught early at startup rather than during runtime.
After defining these errors, you can use them directly in your code by referencing
myerrors.ErrBadRequest
ormyerrors.ErrNotFound
. Since they are pre-initialized at the package level, they are always available without needing additional error handling for creation.
BaseError
in a Custom Type?In Go, it’s common to wrap a base error type inside a more specific domain error type (like UserNotFoundError
). Here’s why this approach is beneficial:
Stronger Type Assertions
When handling errors, using a custom error type allows for better type checking with errors.As()
.
Better Encapsulation of Business Logic
A custom error type keeps domain logic inside the error itself, making it easier to manage.
Improves Readability & Maintains Domain Clarity
Without a Custom Error Type:
With a Custom Error Type:
Adding Context with a Prefix: Use errors.WrapErrorWithPrefix
to add context to an error with a specified prefix. This helps in tracking where the error occurred. If the error is nil, it does nothing.
Wrapping Errors: Use errors.WrapError
to combine multiple errors into one. If either error is nil, it returns the non-nil error. If both are non-nil, it wraps the new error around the original error.
Unwrapping Domain Errors: Use errors.UnwrapDomainError
to extract the DomainError
from an error chain, allowing for specialized handling of domain-specific errors.
Error codes follow the xyyzzz
format:
x
: Main category (e.g., 4 for Client Errors).
yy
: Subcategory (e.g., 01 for Bad Request Errors).
zzz
: Specific error code (e.g., 001 for a particular invalid parameter).
Example:
401001
could represent an invalid username parameter.
Defined categories and their descriptions:
200zzz
: Success
201zzz
: Partial Success
202zzz
: Accepted
400zzz
: Client Errors
401zzz
: Bad Request
402zzz
: Not Found
403zzz
: Conflict
404zzz
: Unprocessable Entity
500zzz
: Server Errors
501zzz
: Database Errors
502zzz
: 3rd Party Errors
503zzz
: Service Unavailable
900zzz
: Security Errors
901zzz
: Unauthorized
902zzz
: Forbidden
The validCategories map in
categories.go
maintains the valid categories and their descriptions.
Consistency: Always define error codes and messages in a centralized place to maintain consistency.
Embedding BaseError: Ensure all custom errors embed *errors.BaseError
to integrate with the error handling utilities.
Category Alignment: When defining new error codes, make sure they align with the predefined categories and use the correct HTTP status codes.
Avoid Manual Synchronization: Use the centralized data structures for categories and error codes to prevent inconsistencies.
You can find a complete working example in the repository under .