Bug
The lint "type switch on error will fail on wrapped errors" triggers even when you check the Unwrap interfaces.
Error message
Error: example.go:27:14: type switch on error will fail on wrapped errors. Use errors.As to check for specific errors (errorlint)
switch x := err.(type) {
Short example
func ParseAllErr(err error) {
switch x := err.(type) {
case interface{ Unwrap() error }:
fmt.Printf("single unwrap err: %s\n", err)
case interface{ Unwrap() []error }:
for _, e := range x.Unwrap() {
if e != nil {
fmt.Printf("multi-error found: %s\n", e)
ParseAllErr(e)
}
}
default:
// Specific handling for non wrapping errors
fmt.Printf("error without Unwrap: %s\n", err)
}
}
func main() {
err := errors.Join(
SingleError{Err: errors.New("one")},
MultiError{Err: errors.New("two"), Err2: errors.New("three")},
)
ParseAllErr(err)
}
Runnable example
More fleshed out example in playground: https://go.dev/play/p/X7xE6VILmY9
package main
import (
"errors"
"fmt"
)
type SingleError struct {
Err error
}
type MultiError struct {
Err error
Err2 error
}
func (s SingleError) Error() string {
return s.Err.Error()
}
func (s SingleError) Unwrap() error {
return s.Err
}
func (m MultiError) Error() string {
return fmt.Sprintf("%v, %v", m.Err, m.Err2)
}
func (m MultiError) Unwrap() []error {
return []error{m.Err, m.Err2}
}
func ParseAllErr(err error) {
switch x := err.(type) {
case interface{ Unwrap() error }:
fmt.Printf("single unwrap err: %s\n", err)
case interface{ Unwrap() []error }:
for _, e := range x.Unwrap() {
if e != nil {
fmt.Printf("multi-error found: %s\n", e)
ParseAllErr(e)
}
}
default:
// Specific handling for non wrapping errors
fmt.Printf("error without Unwrap: %s\n", err)
}
}
func main() {
err := errors.Join(
SingleError{Err: errors.New("one")},
MultiError{Err: errors.New("two"), Err2: errors.New("three")},
MultiError{
Err: errors.New("four"),
Err2: MultiError{
Err: errors.New("five"),
Err2: errors.New("six"),
},
},
)
ParseAllErr(err)
}
Workaround
You can use errors.As with the interfaces to get around the linter in some cases.
var unwrappable interface{ Unwrap() error }
if errors.As(err, &unwrappable) { // handling }
var multiUnwrappable interface{ Unwrap() []error }
if errors.As(err, &multiUnwrappable) { //handling }
If we were to create a breadth first version of errors.As then we would need to write code like the examples that trigger the lint.
Bug
The lint "type switch on error will fail on wrapped errors" triggers even when you check the Unwrap interfaces.
Error message
Error: example.go:27:14: type switch on error will fail on wrapped errors. Use errors.As to check for specific errors (errorlint)
switch x := err.(type) {
Short example
Runnable example
More fleshed out example in playground: https://go.dev/play/p/X7xE6VILmY9
Workaround
You can use errors.As with the interfaces to get around the linter in some cases.
If we were to create a breadth first version of
errors.Asthen we would need to write code like the examples that trigger the lint.