xerr is a clean, robust, and enterprise‑grade error handling framework for Go applications. It provides a predictable, expressive, and type‑safe way to represent errors across your entire stack — from domain logic all the way to HTTP delivery layers.
Built for real‑world backend architectures (DDD, Clean Architecture, microservices), xerr helps you:
- 🧩 Standardize error shapes across all layers
- 🎯 Attach metadata for debugging and observability
- 📡 Cleanly expose errors in JSON form over HTTP
- 🧠 Work seamlessly with
errors.Is/errors.As - 🧵 Preserve underlying error chains
- ⚡ Enrich errors dynamically with functional options
- 🔒 Safely hide internal error details from clients
Ensures strict encapsulation and prevents accidental mutation.
Build expressive, context‑rich errors without clutter.
errors.Is, errors.As, and Unwrap work flawlessly.
Uses a custom MarshalJSON method to expose only safe fields.
Every error maps to an appropriate HTTP status code.
Pure Go. Zero bells and whistles. Maximum clarity.
go get github.com/Ali127Dev/xerrerr := xerr.New(
xerr.CodeValidationFailed,
xerr.WithMessage("email format is invalid"),
xerr.WithMeta("field", "email"),
)Wrapped error:
if err := db.First(&u).Error; err != nil {
return xerr.Wrap(err, xerr.CodeNotFound,
xerr.WithMessage("user not found"),
xerr.WithMeta("user_id", userID),
)
}Errors automatically serialize into a clean client‑safe format:
{
"code": "VALIDATION_FAILED",
"message": "email format is invalid",
"meta": { "field": "email" }
}Internal fields like err and status are hidden.
Creates a fresh structured error.
Wraps an underlying Go error with your business/domain error.
Human‑readable error description.
Override HTTP status mapping.
Attach arbitrary structured metadata.
Attach an underlying error without exposing it.
The error string prioritizes fields in this order:
- Custom message
- Underlying
err.Error() - The code value
Example:
fmt.Println(err.Error())
// VALIDATION_FAILED: email format is invalidfunc ErrorHandler(c *gin.Context) {
c.Next()
if len(c.Errors) == 0 {
return
}
err := c.Errors.Last().Err
xe, ok := err.(*xerr.Error)
if !ok { // convert native errors automatically
xe = xerr.Wrap(err, xerr.CodeInternal)
}
c.JSON(xe.HTTPStatus(), xe)
}xerr provides a dedicated DTO for API documentation to ensure consistent and properly documented error responses in Swagger / OpenAPI.
type SwaggerErrOutput struct {
Code Code `json:"code" example:"INVALID_ARGUMENT"`
Message string `json:"message,omitempty" example:"invalid request body"`
Meta map[string]any `json:"meta,omitempty" example:"field=username"`
} // @name ErrorAlthough xerr.Error already controls JSON serialization via MarshalJSON,
Swagger generators (like swaggo/swag) rely on struct definitions for schema generation.
SwaggerErrOutput exists purely for documentation purposes and ensures:
- ✅ Stable and predictable OpenAPI schema
- ✅ Accurate example values in Swagger UI
- ✅ No leakage of internal fields (err, status)
- ✅ Clear API contract for frontend teams
// @Failure 400 {object} xerr.SwaggerErrOutput
// @Failure 401 {object} xerr.SwaggerErrOutput
// @Failure 500 {object} xerr.SwaggerErrOutput{
"code": "INVALID_ARGUMENT",
"message": "invalid request body",
"meta": {
"field": "username"
}
}
- 📘 Perfect for Clean Architecture
- 🧱 Works beautifully with domain‑driven design
- 🚦 Rich metadata for observability
- 🎯 Predictable structure for frontend consumption
- 📡 Ideal for microservices and HTTP APIs
Pull requests and feature ideas are welcome! Help make error handling in Go beautiful.
MIT — Do whatever you want. Build cool stuff.
xerr is built for developers who want consistency, clarity, and confidence across their entire Go backend.
If that’s you — welcome aboard 🚀🔥