This repository was archived by the owner on Nov 10, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 20
This repository was archived by the owner on Nov 10, 2025. It is now read-only.
False positive if err.(type) switch checks Unwrap interfaces #88
Copy link
Copy link
Open
Description
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.
MrAlias
Metadata
Metadata
Assignees
Labels
No labels