263 lines
6.2 KiB
Go
263 lines
6.2 KiB
Go
package merrors
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type definedError string
|
|
|
|
func (e definedError) Error() string {
|
|
return string(e)
|
|
}
|
|
|
|
type wrappedError struct {
|
|
base error
|
|
msg string
|
|
}
|
|
|
|
// opaqueWrappedError preserves error classification and causal inspection
|
|
// without including the cause text in Error. Use it at boundaries where a
|
|
// storage or provider error can contain secrets or sensitive identifiers.
|
|
type opaqueWrappedError struct {
|
|
base error
|
|
cause error
|
|
msg string
|
|
}
|
|
|
|
func (e wrappedError) Error() string {
|
|
baseText := ""
|
|
if e.base != nil {
|
|
baseText = strings.TrimSpace(e.base.Error())
|
|
}
|
|
msg := strings.TrimSpace(e.msg)
|
|
|
|
switch {
|
|
case baseText == "":
|
|
return msg
|
|
case msg == "":
|
|
return baseText
|
|
default:
|
|
return baseText + ": " + msg
|
|
}
|
|
}
|
|
|
|
func (e wrappedError) Unwrap() error {
|
|
return e.base
|
|
}
|
|
|
|
func (e opaqueWrappedError) Error() string {
|
|
return Wrap(e.base, e.msg).Error()
|
|
}
|
|
|
|
func (e opaqueWrappedError) Unwrap() []error {
|
|
causes := make([]error, 0, 2)
|
|
if e.base != nil {
|
|
causes = append(causes, e.base)
|
|
}
|
|
if e.cause != nil {
|
|
causes = append(causes, e.cause)
|
|
}
|
|
return causes
|
|
}
|
|
|
|
func Define(msg string) error {
|
|
return definedError(msg)
|
|
}
|
|
|
|
func Message(msg string) error {
|
|
return definedError(msg)
|
|
}
|
|
|
|
func Messagef(format string, args ...any) error {
|
|
return Message(fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
func Wrap(err error, msg string) error {
|
|
return wrappedError{
|
|
base: err,
|
|
msg: msg,
|
|
}
|
|
}
|
|
|
|
func Wrapf(err error, format string, args ...any) error {
|
|
return Wrap(err, fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
// OpaqueWrap adds safe context while retaining the cause for errors.Is and
|
|
// errors.As. Unlike Wrap, it deliberately excludes the cause text from Error.
|
|
func OpaqueWrap(base, cause error, msg string) error {
|
|
return opaqueWrappedError{base: base, cause: cause, msg: msg}
|
|
}
|
|
|
|
var ErrNotImplemented = Define("notImplemented")
|
|
|
|
func NotImplemented(msg string) error {
|
|
return Wrap(ErrNotImplemented, msg)
|
|
}
|
|
|
|
var ErrNoData = Define("noData")
|
|
|
|
func NoData(msg string) error {
|
|
return Wrap(ErrNoData, msg)
|
|
}
|
|
|
|
func NoDataf(format string, args ...any) error {
|
|
return NoData(fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
var ErrInternal = Define("internal")
|
|
|
|
func Internal(msg string) error {
|
|
return Wrap(ErrInternal, msg)
|
|
}
|
|
|
|
func Internalf(format string, args ...any) error {
|
|
return Internal(fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
var ErrInvalidArg = Define("invalidArgError")
|
|
|
|
func InvalidArgument(msg string, argumentNames ...string) error {
|
|
return Wrap(ErrInvalidArg, invalidArgumentMessage(msg, argumentNames...))
|
|
}
|
|
|
|
func InvalidArgumentf(format string, args ...any) error {
|
|
return InvalidArgument(fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
func InvalidArgumentWithNamesf(argumentNames []string, format string, args ...any) error {
|
|
return InvalidArgument(fmt.Sprintf(format, args...), argumentNames...)
|
|
}
|
|
|
|
var ErrDataConflict = Define("dataConflict")
|
|
|
|
func DataConflict(msg string) error {
|
|
return Wrap(ErrDataConflict, msg)
|
|
}
|
|
|
|
func DataConflictf(format string, args ...any) error {
|
|
return DataConflict(fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
func DataConflictWrap(err error, msg string) error {
|
|
return wrapError(ErrDataConflict, msg, err)
|
|
}
|
|
|
|
func DataConflictWrapf(err error, format string, args ...any) error {
|
|
return DataConflictWrap(err, fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
var ErrFailedPrecondition = Define("failedPrecondition")
|
|
|
|
func FailedPrecondition(msg string) error {
|
|
return Wrap(ErrFailedPrecondition, msg)
|
|
}
|
|
|
|
func FailedPreconditionf(format string, args ...any) error {
|
|
return FailedPrecondition(fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
func FailedPreconditionWrap(err error, msg string) error {
|
|
return wrapError(ErrFailedPrecondition, msg, err)
|
|
}
|
|
|
|
func FailedPreconditionWrapf(err error, format string, args ...any) error {
|
|
return FailedPreconditionWrap(err, fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
var ErrServiceUnavailable = Define("serviceUnavailable")
|
|
|
|
func ServiceUnavailable(msg string) error {
|
|
return Wrap(ErrServiceUnavailable, msg)
|
|
}
|
|
|
|
func ServiceUnavailablef(format string, args ...any) error {
|
|
return ServiceUnavailable(fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
func ServiceUnavailableWrap(err error, msg string) error {
|
|
return wrapError(ErrServiceUnavailable, msg, err)
|
|
}
|
|
|
|
func ServiceUnavailableWrapf(err error, format string, args ...any) error {
|
|
return ServiceUnavailableWrap(err, fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
type objectRef interface {
|
|
IsZero() bool
|
|
Hex() string
|
|
}
|
|
|
|
var ErrAccessDenied = Define("accessDenied")
|
|
|
|
func PermissionDenied(msg string) error {
|
|
return Wrap(ErrAccessDenied, msg)
|
|
}
|
|
|
|
func AccessDenied(object, action string, ref objectRef) error {
|
|
if ref != nil && !ref.IsZero() {
|
|
return Wrap(ErrAccessDenied, fmt.Sprintf("cannot %s object of type '%s' with ID '%s'", action, object, ref.Hex()))
|
|
}
|
|
return Wrap(ErrAccessDenied, fmt.Sprintf("cannot %s object of type '%s'", action, object))
|
|
}
|
|
|
|
var ErrInvalidDataType = Define("invalidDataType")
|
|
|
|
func InvalidDataType(msg string) error {
|
|
return Wrap(ErrInvalidDataType, msg)
|
|
}
|
|
|
|
func InvalidDataTypef(format string, args ...any) error {
|
|
return InvalidDataType(fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
var ErrUnauthorized = Define("unathorized")
|
|
|
|
func Unauthorized(msg string) error {
|
|
return Wrap(ErrUnauthorized, msg)
|
|
}
|
|
|
|
func Unauthorizedf(format string, args ...any) error {
|
|
return Unauthorized(fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
func InvalidArgumentWrap(err error, msg string, argumentNames ...string) error {
|
|
return wrapError(ErrInvalidArg, invalidArgumentMessage(msg, argumentNames...), err)
|
|
}
|
|
|
|
func InvalidArgumentWrapf(err error, format string, args ...any) error {
|
|
return InvalidArgumentWrap(err, fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
func InternalWrap(err error, msg string) error {
|
|
return wrapError(ErrInternal, msg, err)
|
|
}
|
|
|
|
func InternalWrapf(err error, format string, args ...any) error {
|
|
return InternalWrap(err, fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
func InternalWrapAll(msg string, errs ...error) error {
|
|
return wrapErrors(ErrInternal, msg, errs...)
|
|
}
|
|
|
|
func wrapError(base error, msg string, err error) error {
|
|
return wrapErrors(base, msg, err)
|
|
}
|
|
|
|
func wrapErrors(base error, msg string, errs ...error) error {
|
|
baseErr := Wrap(base, msg)
|
|
causes := make([]error, 0, len(errs))
|
|
for _, err := range errs {
|
|
if err != nil {
|
|
causes = append(causes, err)
|
|
}
|
|
}
|
|
if len(causes) == 0 {
|
|
return baseErr
|
|
}
|
|
return errors.Join(baseErr, errors.Join(causes...))
|
|
}
|