Last active
June 28, 2022 16:29
-
-
Save BenjamenMeyer/ef9926913dcc3b165da8f25a459442a9 to your computer and use it in GitHub Desktop.
golang error wrapping
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"errors" | |
"fmt" | |
) | |
var ( | |
Err1 error = errors.New("Err1") | |
Err2 error = errors.New("Err2") | |
Err3 error = errors.New("Err3") | |
Err4 error = errors.New("Err4") | |
) | |
func getSumErr() []error { | |
return []error{ | |
Err1, | |
Err2, | |
Err3, | |
Err4, | |
} | |
} | |
func checkForErrors(theErr error, allErrors []error) { | |
fmt.Printf("Final error: %v\n", theErr) | |
for _, ae := range allErrors { | |
if errors.Is(theErr, ae) { | |
fmt.Printf("Found %v\n", ae) | |
} else { | |
fmt.Printf("Did NOT find %v\n", ae) | |
} | |
} | |
} | |
func method1() { | |
sumErrs := getSumErr() | |
genErr := fmt.Errorf("My final error. verr: %w", sumErrs) | |
checkForErrors(genErr, sumErrs) | |
} | |
func method2() { | |
sumErrs := getSumErr() | |
genErr := fmt.Errorf("My final error") | |
for _, se := range sumErrs { | |
genErr = fmt.Errorf("%v: %w", genErr, se) | |
} | |
checkForErrors(genErr, sumErrs) | |
} | |
func main() { | |
fmt.Println("Method 1") | |
method1() | |
fmt.Println("Method 2") | |
method2() | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Method 1 | |
Final error: My final error. verr: %!w([]error=[0xc000010250 0xc000010260 0xc000010270 0xc000010280]) | |
Did NOT find Err1 | |
Did NOT find Err2 | |
Did NOT find Err3 | |
Did NOT find Err4 | |
Method 2 | |
Final error: My final error: Err1: Err2: Err3: Err4 | |
Did NOT find Err1 | |
Did NOT find Err2 | |
Did NOT find Err3 | |
Found Err4 | |
Program exited. |
NOTE: Consider that the code receiving genErr
doesn't know anything about the code that's generated Err1
, Err2
, and Err3
but the code generating Err4
noted their existing in its documentation. This could be for multiple reasons - Err2 could be a File not opened
type error with Err3
and Err4
providing more details. The handler may or may not be able to do something about Err2
but it has to be able to detect it first. This promotes error re-use:
var ErrSomeErr error = errors.New("some error")
...
return fmt.Errorf("%w: some detail", ErrSomeErr)
...
return fmt.Errorf("%w: some more details", wrappedErrSomeErr)
...
return fmt.Errorf("%w: some other detail", wrappedWrappedErrSomeErr)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
NOTES:
getSumErr()
as the errors built up throughout the code when an error is returnedgenErr
as sent tocheckForErrors()
as the final error seen by the layer testing for an errorUnfortunately currently (Golang 1.18) can't detect that the earlier errors (Err1, Err2, Err3) are part of the error.
I even tried adding:
However, that pulls out
Err4
:The other errors are not unwrapped. Perhaps proposals like golang/go#53435 can help solve that in future versions of Golang.