Skip to main content
The Errors API provides a structured error system with HTTP status codes and gRPC status integration.

Types

Error

Status error with code, reason, message, and metadata.
type Error struct {
    Status
    // contains filtered or unexported fields
}

type Status struct {
    Code     int32             `json:"code"`
    Reason   string            `json:"reason"`
    Message  string            `json:"message"`
    Metadata map[string]string `json:"metadata"`
}
Code
int32
HTTP status code
Reason
string
Error reason identifier
Message
string
Human-readable error message
Metadata
map[string]string
Additional error metadata

Constants

const (
    UnknownCode   = 500
    UnknownReason = ""
)

Functions

New

Creates a new error.
func New(code int, reason, message string) *Error
code
int
HTTP status code
reason
string
Error reason identifier
message
string
Error message
error
*Error
New Error instance
Example:
err := errors.New(404, "USER_NOT_FOUND", "User not found")

Newf

Creates a new error with formatted message.
func Newf(code int, reason, format string, a ...any) *Error
Example:
err := errors.Newf(404, "USER_NOT_FOUND", "User %s not found", userID)

Errorf

Creates an error with formatted message.
func Errorf(code int, reason, format string, a ...any) error

FromError

Converts any error to *Error.
func FromError(err error) *Error
err
error
Error to convert. Supports wrapped errors.
error
*Error
Converted Error instance
Example:
if err != nil {
    e := errors.FromError(err)
    fmt.Printf("Code: %d, Reason: %s\n", e.Code, e.Reason)
}

Code

Returns the HTTP code for an error.
func Code(err error) int
err
error
Error to extract code from
code
int
HTTP status code (200 if err is nil)

Reason

Returns the reason for an error.
func Reason(err error) string
err
error
Error to extract reason from
reason
string
Error reason identifier

Clone

Deep clones an error.
func Clone(err *Error) *Error

Error Methods

Error

Returns the error string.
func (e *Error) Error() string

Unwrap

Provides compatibility for Go 1.13 error chains.
func (e *Error) Unwrap() error

Is

Matches each error in the chain.
func (e *Error) Is(err error) bool

WithCause

Adds the underlying cause.
func (e *Error) WithCause(cause error) *Error
Example:
dbErr := sql.ErrNoRows
err := errors.NotFound("USER_NOT_FOUND", "User not found").WithCause(dbErr)

WithMetadata

Adds metadata to the error.
func (e *Error) WithMetadata(md map[string]string) *Error
Example:
err := errors.BadRequest("INVALID_INPUT", "Invalid input").WithMetadata(map[string]string{
    "field": "email",
    "rule": "format",
})

GRPCStatus

Returns the gRPC status.
func (e *Error) GRPCStatus() *status.Status

HTTP Status Code Constructors

BadRequest (400)

func BadRequest(reason, message string) *Error
func IsBadRequest(err error) bool

Unauthorized (401)

func Unauthorized(reason, message string) *Error
func IsUnauthorized(err error) bool

Forbidden (403)

func Forbidden(reason, message string) *Error
func IsForbidden(err error) bool

NotFound (404)

func NotFound(reason, message string) *Error
func IsNotFound(err error) bool

Conflict (409)

func Conflict(reason, message string) *Error
func IsConflict(err error) bool

TooManyRequests (429)

func TooManyRequests(reason, message string) *Error
func IsTooManyRequests(err error) bool

ClientClosed (499)

func ClientClosed(reason, message string) *Error
func IsClientClosed(err error) bool

InternalServer (500)

func InternalServer(reason, message string) *Error
func IsInternalServer(err error) bool

ServiceUnavailable (503)

func ServiceUnavailable(reason, message string) *Error
func IsServiceUnavailable(err error) bool

GatewayTimeout (504)

func GatewayTimeout(reason, message string) *Error
func IsGatewayTimeout(err error) bool

Usage Examples

Creating Errors

package main

import (
    "github.com/go-kratos/kratos/v2/errors"
)

func GetUser(id string) (*User, error) {
    user, err := db.FindUser(id)
    if err != nil {
        return nil, errors.NotFound("USER_NOT_FOUND", "User not found").WithCause(err)
    }
    return user, nil
}

func CreateUser(req *CreateUserRequest) error {
    if req.Email == "" {
        return errors.BadRequest(
            "INVALID_EMAIL",
            "Email is required",
        ).WithMetadata(map[string]string{
            "field": "email",
        })
    }
    return nil
}

Error Checking

func handleError(err error) {
    if errors.IsNotFound(err) {
        // Handle not found
        fmt.Println("Resource not found")
        return
    }
    
    if errors.IsUnauthorized(err) {
        // Handle unauthorized
        fmt.Println("Unauthorized access")
        return
    }
    
    // Check error code
    code := errors.Code(err)
    reason := errors.Reason(err)
    fmt.Printf("Error: code=%d, reason=%s\n", code, reason)
}

Error Conversion

func convertError(err error) *errors.Error {
    // Convert any error to Kratos error
    e := errors.FromError(err)
    
    // Access error details
    fmt.Printf("Code: %d\n", e.Code)
    fmt.Printf("Reason: %s\n", e.Reason)
    fmt.Printf("Message: %s\n", e.Message)
    
    for k, v := range e.Metadata {
        fmt.Printf("Metadata %s: %s\n", k, v)
    }
    
    return e
}

HTTP Handler Integration

func (s *Server) GetUser(ctx context.Context, req *GetUserRequest) (*User, error) {
    user, err := s.userService.Get(ctx, req.Id)
    if err != nil {
        // Return appropriate error
        if err == sql.ErrNoRows {
            return nil, errors.NotFound(
                "USER_NOT_FOUND",
                "User not found",
            ).WithCause(err)
        }
        return nil, errors.InternalServer(
            "DATABASE_ERROR",
            "Failed to query user",
        ).WithCause(err)
    }
    return user, nil
}

Error Chaining

func processOrder(orderID string) error {
    // Original error from database
    err := db.LockOrder(orderID)
    if err != nil {
        // Wrap with application error
        return errors.Conflict(
            "ORDER_LOCKED",
            "Order is being processed",
        ).WithCause(err)
    }
    return nil
}

// Later in the code
err := processOrder("123")
if err != nil {
    // Can check both the application error and the cause
    if errors.IsConflict(err) {
        e := errors.FromError(err)
        // Access the original error via Unwrap
        originalErr := e.Unwrap()
    }
}

Build docs developers (and LLMs) love