Skip to content

errors: errors.Join does not skip nil error interface implementations #70626

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
VolkerLieber opened this issue Dec 1, 2024 · 3 comments
Closed

Comments

@VolkerLieber
Copy link

VolkerLieber commented Dec 1, 2024

Go version

go1.23.0

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/root/.cache/go-build'
GOENV='/root/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/root/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/root/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/snap/go/10743'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/snap/go/10743/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.23.3'
GODEBUG=''
GOTELEMETRY='local'
GOTELEMETRYDIR='/root/.config/go/telemetry'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/root/errors-test/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1931872224=/tmp/go-build -gno-record-gcc-switches'

What did you do?

package main

import (
	"errors"
	"reflect"
	"testing"
)

// Error interface implementation
type TestError struct {
}

func (te TestError) Error() string {
	return "test error"
}

func TestJoin(t *testing.T) {
	err1 := errors.New("err1")
	err2 := errors.New("err2")

	var nilerror *TestError

	for _, test := range []struct {
		errs []error
		want []error
	}{{
		errs: []error{err1, nilerror, err2},
		want: []error{err1, err2},
	}} {
		got := errors.Join(test.errs...).(interface{ Unwrap() []error }).Unwrap()
		if !reflect.DeepEqual(got, test.want) {
			t.Errorf("Join(%v) = %v; want %v", test.errs, got, test.want)
		}
		if len(got) != cap(got) {
			t.Errorf("Join(%v) returns errors with len=%v, cap=%v; want len==cap", test.errs, len(got), cap(got))
		}
	}
}

What did you see happen?

Join([err1 err2]) = [err1 err2]; want [err1 err2]

What did you expect to see?

ok

The err!=nil check returns false for all passed nil pointers to an error interface implementation, resulting in the nil error being included in the constructed error.

@VolkerLieber
Copy link
Author

Ok, thanks to the linked tickets, it seems like this is "intended": https://go.dev/doc/faq#nil_error
This still seems to me like a bug rather than a feature.
What do you think?

@seankhliao
Copy link
Member

It's consistent with how other error checks work

@seankhliao seankhliao closed this as not planned Won't fix, can't repro, duplicate, stale Dec 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants