Skip to content

os/exec: .Run() should not return as error on non-zero status on *NIX-like platforms #51123

@johnnybubonic

Description

@johnnybubonic

What version of Go are you using (go version)?

$ go version
go version go1.17.6 linux/amd64

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="amd64"
GOBIN=""
GOCACHE="/home/[REDACTED]/.cache/go-build"
GOENV="/home/[REDACTED]/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/[REDACTED]/go/pkg/mod"
GONOPROXY="[REDACTED],[REDACTED]/*,github.com/[REDACTED]/*"
GONOSUMDB="[REDACTED],[REDACTED]/*,github.com/[REDACTED]/*"
GOOS="linux"
GOPATH="/opt/dev/go"
GOPRIVATE="[REDACTED],[REDACTED]/*,github.com/[REDACTED]/*"
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/lib/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.17.6"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/[REDACTED]/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build1498898721=/tmp/go-build -gno-record-gcc-switches"

What did you do?

N/A; bug in design.

exec.Cmd.Run() currently returns an error on non-zero exit status.

This is not only poor design logic as many commands return non-zero even upon success, but it hampers access to getting the status code of a command- requiring .Wait() to be invoked instead.

A careful note is that it's common assumption that POSIX or some other standard defines 0 as success and n > 0 as failure. To stress, this is erroneous - it is convention, not standard.

An immediate example that comes to mind is sendmail's EX_TEMPFAIL, status code 75. This indicates that a message was deferred, not failed, and will be retried (or the user should retry, depending on your MTA spooling or lack thereof).

What did you expect to see?

N/A

What did you see instead?

N/A

Proposed Resolution

I propose the following.

Obviously changing e.g. exec.Run() execution with a non-zero exit code flagging an error is not the proper way forward, as that's a significant API interface change that likely many people are depending on.

Instead, there should be "non-erroring" methods added, e.g. .RunNonZero() and .WaitNonZero() (I'm not crazy about the names, but...) that will return the *os.ProcessState (nil if error NOT related to command exit code) and error (NOT returned if command has non-zero exit code).

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeWaitingForInfoIssue is not actionable because of missing required information, which needs to be provided.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions