From 79c41966afc77b920e8493f457e3f85317943666 Mon Sep 17 00:00:00 2001 From: Srigovind Nayak <5201843+konidev20@users.noreply.github.com> Date: Sat, 19 Apr 2025 14:13:50 +0530 Subject: [PATCH] errors: enhance fatalError type to include underlying errors --- internal/errors/fatal.go | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/internal/errors/fatal.go b/internal/errors/fatal.go index 9370a68d7..12b310aca 100644 --- a/internal/errors/fatal.go +++ b/internal/errors/fatal.go @@ -7,25 +7,48 @@ import ( // fatalError is an error that should be printed to the user, then the program // should exit with an error code. -type fatalError string +type fatalError struct { + msg string + err error // Underlying error +} -func (e fatalError) Error() string { - return string(e) +func (e *fatalError) Error() string { + return e.msg +} + +func (e *fatalError) Unwrap() error { + return e.err } // IsFatal returns true if err is a fatal message that should be printed to the // user. Then, the program should exit. func IsFatal(err error) bool { - var fatal fatalError + var fatal *fatalError return errors.As(err, &fatal) } // Fatal returns an error that is marked fatal. func Fatal(s string) error { - return Wrap(fatalError(s), "Fatal") + return Wrap(&fatalError{msg: s}, "Fatal") } -// Fatalf returns an error that is marked fatal. +// Fatalf returns an error that is marked fatal, preserving an underlying error if passed. func Fatalf(s string, data ...interface{}) error { - return Wrap(fatalError(fmt.Sprintf(s, data...)), "Fatal") + // Use the last error found. + var underlyingErr error + for i := len(data) - 1; i >= 0; i-- { + if err, ok := data[i].(error); ok { + underlyingErr = err + break + } + } + + msg := fmt.Sprintf(s, data...) + + fatal := &fatalError{ + msg: msg, + err: underlyingErr, + } + + return Wrap(fatal, "Fatal") }