package model import ( "errors" "fmt" ) var ( ErrNotFound = errors.New("resource not found") ErrDuplicate = errors.New("resource already exists") ErrUnauthorized = errors.New("unauthorized") ErrForbidden = errors.New("forbidden") ErrUploadTooLarge = errors.New("upload exceeds maximum size") ) // ErrorKind classifies domain errors without tying them to a transport. type ErrorKind string // Protocol-neutral error kinds. const ( KindInvalidArgument ErrorKind = "invalid_argument" KindUnauthenticated ErrorKind = "unauthenticated" KindPermissionDenied ErrorKind = "permission_denied" KindNotFound ErrorKind = "not_found" KindConflict ErrorKind = "conflict" KindPayloadTooLarge ErrorKind = "payload_too_large" KindInternal ErrorKind = "internal" ) // AppError is a service-layer error that carries a protocol-neutral kind, a // user-safe message, and an optional internal cause for logging. type AppError struct { Kind ErrorKind Message string Err error } func (e *AppError) Error() string { return e.Message } func (e *AppError) Unwrap() error { return e.Err } // NewInvalidArgumentError creates an invalid-argument AppError. func NewInvalidArgumentError(message string) *AppError { return &AppError{Kind: KindInvalidArgument, Message: message} } // NewBadRequestError creates an invalid-argument AppError. func NewBadRequestError(message string) *AppError { return NewInvalidArgumentError(message) } // NewUnauthenticatedError creates an unauthenticated AppError. func NewUnauthenticatedError(message string) *AppError { return &AppError{Kind: KindUnauthenticated, Message: message} } // NewConflictError creates a conflict AppError. func NewConflictError(message string) *AppError { return &AppError{Kind: KindConflict, Message: message} } // NewNotFoundError creates a not-found AppError. func NewNotFoundError(message string, cause error) *AppError { return &AppError{Kind: KindNotFound, Message: message, Err: cause} } // NewPermissionDeniedError creates a permission-denied AppError. func NewPermissionDeniedError(message string, cause error) *AppError { return &AppError{Kind: KindPermissionDenied, Message: message, Err: cause} } // NewForbiddenError creates a permission-denied AppError. func NewForbiddenError(message string, cause error) *AppError { return NewPermissionDeniedError(message, cause) } // NewPayloadTooLargeError creates a payload-too-large AppError. func NewPayloadTooLargeError(message string, cause error) *AppError { return &AppError{Kind: KindPayloadTooLarge, Message: message, Err: cause} } // NewInternalError creates an internal AppError with a wrapped internal cause. // msg describes the operation that failed; cause is the underlying error. func NewInternalError(msg string, cause error) *AppError { return &AppError{ Kind: KindInternal, Message: "internal server error", Err: fmt.Errorf("%s: %w", msg, cause), } }