Description
What version of Go are you using (go version
)?
$ go version go version go1.21.1 darwin/arm64
Does this issue reproduce with the latest release?
YES.
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env GO111MODULE='' GOARCH='arm64' GOBIN='' GOCACHE='/Users/budougumi0617/Library/Caches/go-build' GOENV='/Users/budougumi0617/Library/Application Support/go/env' GOEXE='' GOEXPERIMENT='' GOFLAGS='' GOHOSTARCH='arm64' GOHOSTOS='darwin' GOINSECURE='' GOMODCACHE='/Users/budougumi0617/go/pkg/mod' GONOPROXY='' GONOSUMDB='' GOOS='darwin' GOPATH='/Users/budougumi0617/go' GOPRIVATE='' GOPROXY='https://proxy.golang.org,direct' GOROOT='/opt/homebrew/Cellar/go/1.21.1/libexec' GOSUMDB='sum.golang.org' GOTMPDIR='' GOTOOLCHAIN='auto' GOTOOLDIR='/opt/homebrew/Cellar/go/1.21.1/libexec/pkg/tool/darwin_arm64' GOVCS='' GOVERSION='go1.21.1' GCCGO='gccgo' AR='ar' CC='cc' CXX='c++' CGO_ENABLED='1' GOMOD='/dev/null' 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 -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/ll/hpp009q97nvdhy4j49dmw96h0000gn/T/go-build623399656=/tmp/go-build -gno-record-gcc-switches -fno-common'
What did you do?
The release notes for Go 1.19 mention the following specification about the "operation was canceled" error in the net
package:
When a net package function returns an "operation was canceled" error, the error will now satisfy
errors.Is(err, context.Canceled)
.
However, when I execute errors.Is(err, context.Canceled)
against the "operation was canceled" error that returns from methods like *Dialer.DialContext
, it does not evaluate to true
. Is this in accordance with the specification?
https://go.dev/play/p/Os-LQrrlUx6
_, err := (&net.Dialer{}).DialContext(ctx, "tcp", "localhost:12345")
t.Logf("error was %q\n", err) // error was "dial tcp: lookup localhost: operation was canceled"
if !errors.Is(err, context.Canceled) {
t.Errorf("%T, was not context.Canceled", err) // *net.OpError, was not context.Canceled
}
Looking at the execution result, it appears that the *net.DNSError
within the *net.OpError
has not implemented the Unwrap
method. If the Err
field in the DNSError
struct retained its value as an error
type, I believe the Is
method of errCanceled
(of type canceledError
) from the net
package would be called, and errors.Is(err, context.Canceled)
would return true
.
https://pkg.go.dev/net#DNSError
type DNSError struct {
Err string // description of the error
Name string // name looked for
Server string // server used
IsTimeout bool // if true, timed out; not all timeouts set this
IsTemporary bool // if true, error is temporary; not all errors set this
IsNotFound bool // if true, host could not be found
}
https://github.com/golang/go/blob/go1.21.1/src/net/net.go#L411-L422
// For both read and write operations.
errCanceled = canceledError{}
ErrWriteToConnected = errors.New("use of WriteTo with pre-connected connection")
)
// canceledError lets us return the same error string we have always
// returned, while still being Is context.Canceled.
type canceledError struct{}
func (canceledError) Error() string { return "operation was canceled" }
func (canceledError) Is(err error) bool { return err == context.Canceled }
- ref: net: make errCanceled and errTimeout be "errors.Is" context.Canceled and context.DeadlineExceeded #51428
- ref: net: expose context Canceled/DeadlineExceeded error #36208
What did you expect to see?
When a net package function returns an "operation was canceled" error, errors.Is(err, context.Canceled)
returns true
.
What did you see instead?
When a net package function returns an "operation was canceled" error, errors.Is(err, context.Canceled)
returns false
.