2023-01-30 21:22:45 +00:00
|
|
|
// Copyright (c) Tailscale Inc & AUTHORS
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
|
|
|
|
// Package vizerror provides types and utility funcs for handling visible errors
|
|
|
|
// that are safe to display to end users.
|
|
|
|
package vizerror
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Error is an error that is safe to display to end users.
|
2023-02-01 00:01:02 +00:00
|
|
|
type Error struct {
|
2024-10-09 18:05:33 +01:00
|
|
|
publicErr error // visible to end users
|
|
|
|
wrapped error // internal
|
2023-02-01 00:01:02 +00:00
|
|
|
}
|
|
|
|
|
2024-10-09 18:05:33 +01:00
|
|
|
// Error implements the error interface. The returned string is safe to display
|
|
|
|
// to end users.
|
2023-02-01 00:01:02 +00:00
|
|
|
func (e Error) Error() string {
|
2024-10-09 18:05:33 +01:00
|
|
|
return e.publicErr.Error()
|
2023-02-01 00:01:02 +00:00
|
|
|
}
|
|
|
|
|
2023-02-01 18:38:45 +00:00
|
|
|
// New returns an error that formats as the given text. It always returns a vizerror.Error.
|
2024-10-09 18:05:33 +01:00
|
|
|
func New(publicMsg string) error {
|
|
|
|
err := errors.New(publicMsg)
|
|
|
|
return Error{
|
|
|
|
publicErr: err,
|
|
|
|
wrapped: err,
|
|
|
|
}
|
2023-02-01 00:01:02 +00:00
|
|
|
}
|
|
|
|
|
2024-10-09 18:05:33 +01:00
|
|
|
// Errorf returns an Error with the specified publicMsgFormat and values. It always returns a vizerror.Error.
|
|
|
|
//
|
|
|
|
// Warning: avoid using an error as one of the format arguments, as this will cause the text
|
|
|
|
// of that error to be displayed to the end user (which is probably not what you want).
|
|
|
|
func Errorf(publicMsgFormat string, a ...any) error {
|
|
|
|
err := fmt.Errorf(publicMsgFormat, a...)
|
|
|
|
return Error{
|
|
|
|
publicErr: err,
|
|
|
|
wrapped: err,
|
|
|
|
}
|
2023-02-01 00:01:02 +00:00
|
|
|
}
|
2023-01-30 21:22:45 +00:00
|
|
|
|
2023-02-01 00:01:02 +00:00
|
|
|
// Unwrap returns the underlying error.
|
2024-10-09 18:05:33 +01:00
|
|
|
//
|
|
|
|
// If the Error was constructed using [WrapWithMessage], this is the wrapped (internal) error
|
|
|
|
// and not the user-visible error message.
|
2023-02-01 00:01:02 +00:00
|
|
|
func (e Error) Unwrap() error {
|
2024-10-09 18:05:33 +01:00
|
|
|
return e.wrapped
|
2023-01-30 21:22:45 +00:00
|
|
|
}
|
|
|
|
|
2024-10-09 18:05:33 +01:00
|
|
|
// Wrap wraps publicErr with a vizerror.Error.
|
|
|
|
//
|
|
|
|
// Deprecated: this is almost always the wrong thing to do. Are you really sure
|
|
|
|
// you know exactly what err.Error() will stringify to and be safe to show to
|
|
|
|
// users? [WrapWithMessage] is probably what you want.
|
|
|
|
func Wrap(publicErr error) error {
|
|
|
|
if publicErr == nil {
|
2023-02-01 18:14:36 +00:00
|
|
|
return nil
|
|
|
|
}
|
2024-10-09 18:05:33 +01:00
|
|
|
return Error{publicErr: publicErr, wrapped: publicErr}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WrapWithMessage wraps the given error with a message that's safe to display
|
|
|
|
// to end users. The text of the wrapped error will not be displayed to end
|
|
|
|
// users.
|
|
|
|
//
|
|
|
|
// WrapWithMessage should almost always be preferred to [Wrap].
|
|
|
|
func WrapWithMessage(wrapped error, publicMsg string) error {
|
|
|
|
return Error{
|
|
|
|
publicErr: errors.New(publicMsg),
|
|
|
|
wrapped: wrapped,
|
|
|
|
}
|
2023-01-30 21:22:45 +00:00
|
|
|
}
|
2023-02-01 22:07:24 +00:00
|
|
|
|
|
|
|
// As returns the first vizerror.Error in err's chain.
|
|
|
|
func As(err error) (e Error, ok bool) {
|
|
|
|
ok = errors.As(err, &e)
|
|
|
|
return
|
|
|
|
}
|