Description
Go version
1.23.1, windows/amd64
Output of go env
in your module/workspace:
AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE='on'
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/jma/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/jma/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build134067901=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/home/jma/goShared/go-utils/go.mod'
GOMODCACHE='/home/jma/.gvm/pkgsets/go1.24.1/global/pkg/mod'
GOOS='linux'
GOPATH='/home/jma/.gvm/pkgsets/go1.24.1/global'
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/jma/.gvm/gos/go1.24.1'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/jma/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/jma/.gvm/gos/go1.24.1/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.1'
GOWORK=''
PKG_CONFIG='pkg-config'
What did you do?
The godoc of os/user.Lookup states the following:
// Lookup looks up a user by username. If the user cannot be found, the
// returned error is of type [UnknownUserError].
However, this is not correct on Windows. When tested on Windows Server 2016 / Windows Server 2019 / Windows Server 2022, the Lookup-method fails with the following error message:
No mapping between account names and security IDs was done.
I expected the function to return user.UnknownUserError
.
The error message stems from the Windows Error Code windows.ERROR_NONE_MAPPED
- which specifically states that the account name does not exist.
I tried to manually detect this specific error situation with the following workaround:
func CheckUsernameExists(username string) (bool, error) {
_, err := user.Lookup(username)
if err == nil {
return true, nil // user exists
}
if _, ok := err.(user.UnknownUserError); ok {
return false, nil // user does not exist
}
// Workaround:
var sysErr syscall.Errno
if ok := errors.As(err, &sysErr); ok && sysErr == windows.ERROR_NONE_MAPPED { // "No mapping between account names and security IDs was done."
return false, nil // does not exist
}
return false, err // unknown error
}
However, this does not work either, because user.Lookup does not "wrap" the underlying error (it uses %v
instead of %w
- also for other target platforms).
What did you see happen?
user.Lookup
should return user.UnknownUserError
if Windows produces windows.ERROR_NONE_MAPPED
.
user.Lookup
should also wrap underlying system errors, so that error codes can be inspected.
What did you expect to see?
user.Lookup
embeds the windows error message (string) into the returned error message.