go: embed: go:embed produces error when "go.mod" has go version < 1.16
What version of Go are you using (go version
)?
$ go version go version go1.16rc1 darwin/arm64
Does this issue reproduce with the latest release?
with the rc release? yes.
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env go version go1.16rc1 darwin/arm64 lestrrat@finch jwk % go env GO111MODULE="on" GOARCH="arm64" GOBIN="" GOCACHE="/Users/lestrrat/Library/Caches/go-build" GOENV="/Users/lestrrat/Library/Application Support/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="arm64" GOHOSTOS="darwin" GOINSECURE="" GOMODCACHE="/Users/lestrrat/dev/pkg/mod" GONOPROXY="" GONOSUMDB="" GOOS="darwin" GOPATH="/Users/lestrrat/dev" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/usr/local/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/usr/local/go/pkg/tool/darwin_arm64" GOVCS="" GOVERSION="go1.16rc1" GCCGO="gccgo" AR="ar" CC="clang" CXX="clang++" CGO_ENABLED="1" GOMOD="/Users/lestrrat/dev/src/github.com/lestrrat-go/jwx/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 -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/vb/gf1mcqdd2s509731hrnnvkjm0000gn/T/go-build3140323037=/tmp/go-build -gno-record-gcc-switches -fno-common"
What did you do?
Using github.com/lestrrat-go/jwx@09b6dea (note that it’s at a tracking branch)
lestrrat@finch jwx % cd jwk
lestrrat@finch jwk % go test
What did you expect to see?
lestrrat@finch jwx % cd jwk
lestrrat@finch jwk % go test
PASS
ok github.com/lestrrat-go/jwx/jwk 5.437s
lestrrat@finch jwk %
What did you see instead?
lestrrat@finch jwx % cd jwk
lestrrat@finch jwk % go test
# github.com/lestrrat-go/jwx/jwk_test [github.com/lestrrat-go/jwx/jwk.test]
./fs_test.go:13:3: go:embed requires go1.16 or later (-lang was set to go1.13; check go.mod)
FAIL github.com/lestrrat-go/jwx/jwk [build failed]
lestrrat@finch jwk %
Discussion
My go.mod contains the following
lestrrat@finch jwk % cat ../go.mod
module github.com/lestrrat-go/jwx
go 1.13
require (
github.com/goccy/go-json v0.3.4
github.com/lestrrat-go/backoff/v2 v2.0.7
github.com/lestrrat-go/codegen v1.0.0
github.com/lestrrat-go/httpcc v1.0.0
github.com/lestrrat-go/iter v1.0.0
github.com/lestrrat-go/option v1.0.0
github.com/lestrrat-go/pdebug/v3 v3.0.1
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.6.1
golang.org/dl v0.0.0-20210128152142-7744cb1878f1 // indirect
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620
golang.org/x/mod v0.4.1 // indirect
golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963
)
If I change the line go 1.13
to go 1.16
, then it works on go1.16rc1
lestrrat@finch jwk % go test
# github.com/lestrrat-go/jwx/jwk_test [github.com/lestrrat-go/jwx/jwk.test]
./fs_test.go:13:3: go:embed requires go1.16 or later (-lang was set to go1.13; check go.mod)
FAIL github.com/lestrrat-go/jwx/jwk [build failed]
lestrrat@finch jwk % go mod edit -go 1.16
lestrrat@finch jwk % go test
PASS
ok github.com/lestrrat-go/jwx/jwk 5.648s
lestrrat@finch jwk %
go1.16beta1 worked just fine.
lestrrat@finch jwk % go install golang.org/dl/go1.16beta1
lestrrat@finch jwk % go1.16beta1 download
go1.16beta1: already downloaded in /Users/lestrrat/sdk/go1.16beta1
lestrrat@finch jwk % go1.16beta1 test .
ok github.com/lestrrat-go/jwx/jwk 6.066s
lestrrat@finch jwk %
Shouldn’t features like this just depend on the runtime version, and not contents of go.mod?
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 32 (14 by maintainers)
The expectation is that you don’t use embed until you are ready to bump your users forward. Build tags are not sufficient, precisely because of tools that need to analyze everything, such as
go mod tidy
. The same thing happens (or will happen) with any language change gated by the go.mod version.This is intentional, because a
//go:embed
comment will only work correctly with Go 1.16 or later. A//go:embed
comment requires importing the “embed” package, which is only available in Go 1.16. So compiling a package with an earlier language version will fail.As a developer I often rely on the compiler to tell me when I have broken the code. When I change the signature of a function for instance, the compiler will tell me if I have neglected to fix any call sites.
The fact that it will fail on errors on files guarded by build tags is a good thing. I develop on an intel machine. If my change breaks the build on s390 machines, the compiler will tell me. If it didn’t I might end up shipping code which failed to compile on my first s390 user.
Of course people will tell me I should make sure that my CI system builds and test on every possible permutation of supported architectures, OSes, compiler versions etc. And they may be right. But it is far better that compiler tells me about these problems straight away.
If this issue was “fixed” by allowing the code above to compile without error, it would make development and testing far harder. Please don’t do it.
To @lestrrat, my suggestion would be: if you really have to support Go versions < 1.16, then don’t use embed. In general I would aggressively kill off support for old Go versions, and only use language features and APIs available on the oldest Go version you do support.
The confusion is in the fact that we (well, at least I) have used build tags to switch between certain features that were newly introduced. For example, I have the following successfully compiling in go1.16rc1
In this scenario, I was able to provide support for go 1.14 that doesn’t have
(math/big).FillBytes()
while utilizing the new feature that only appeared in go 1.15At first glance I fail to see the difference between the above and below
(math/big).Int.FillBytes
doesn’t exist in go 1.14, why should it compile, whenimport "embed"
doesn’t? I still think this is inconsistent, but I closed this issue because I realized that this was not something new in go1.16 (and hence unlikely to be changed).Hope that clears up my reasoning on this issue, at least.
I believe that the build tag solution now works correctly with 1.15.11 -
go mod tidy
is now resilient to stdlib imports which don’t exist.For the record, you can work around this issue by declaring
go 1.16
in yourgo.mod
file and using build tags to guard the use ofgo:embed
. For example:Funny enough, I can “workaround” the issue by removing
go 1.11
statement from library’sgo.mod
. 😃https://tip.golang.org/doc/go1.16 explains which new features were added to go1.16 which are not in go1.15. Once 1.16 is released, anything before 1.15 becomes unsupported.
If we try to “help” our users by maintaining a table mapping features to versions, this will in effect be supporting unsupported versions of Go and telling people that it is OK to use them. This effort will be far better spent encouraging the community to upgrade to the current tools.
Having spent little time playing around with
//go:embed
and encountering the error myself, I would say that error message is simple, clear, and reasonable.If you want to use a language feature introduced in Go 1.16, you will need tools >= 1.16 and version 1.16 or greater specified in your go.mod. I may be missing something, but I can’t think of any scenario where someone would want to add embedding while keeping the Go version specified as 1.15 or less.
For reference, that’s #40067, and it even affects users of modules that try and use new standard library packages.
No module can successfully guard its use of a new standard library package with a build tag and have it not still break downstream users with older Go versions. (I expect this to start happening pretty often now that everyone is excited for
embed
, unlike whenmaphash
was added.)