[修正済み] go.modのgoディレクティブにパッチバージョンを含めないと「toolchain not available」と怒られる
(2024.4.20 追記)
注意: 将来のGoでは、パッチバージョンを含めなくてもエラーが出なくなる修正が検討されています。
(2024.5.12 追記)
1.21.11,1.22.4以降で修正されるようです。
以前はgo 1.Xをgo.modに含めるとタイトルのようにビルドできない不具合があり、バージョン指定にパッチバージョンを含めるプラクティスが生まれました。
しかし、1.22.4以降の修正で、デフォルトでgo 1.X.0と解釈されるようになりパッチバージョン含める必要はなくなりました。
タイトルを解決したい方は、記事を読むよりGoをアップデートしましょう。
現象
Go 1.21以降のgo.mod内で、go 1.22のようにパッチバージョンを省略すると goコマンドが失敗します。
$ cat go.mod
module example.com/foo
go 1.22
$ go mod tidy
go: downloading go1.22 (darwin/arm64)
go: download go1.22 for darwin/arm64: toolchain not available
実行例
% GOTOOLCHAIN=local go version
go version go1.21.6 darwin/arm64
解決方法 (兼ベストプラクティス)
go.modのgoディレクティブに指定するGoバージョンにはパッチバージョンを含めましょう。
go 1.22.0
または、toolchainディレクティブを指定しましょう
go 1.22
toolchain go1.22.0
※ 後述しますがtoolchainディレクティブはパッチバージョンが省略できないことに注意
問題の深堀り
前提
Go 1.21以降、goコマンドはgo/toolchainディレクティブのバージョン指定を考慮して、よしなにGoツールチェイン[1]をダウンロードし選択するようになりました。
例えば、go 1.22という行はGo 1.21.Pを許しませんし、toolchain go1.22.1という行は、Go 1.22.0というツールチェインでビルドすることを許しません。
ここで以下に注意してください。
-
goとtoolchainディレクティブの違い-
goディレクティブはGoバージョンを指定する。例:1.22.0,1.22,1.22rc1 -
toolchainディレクティブはGoツールチェイン名を指定する。例:go1.22.0
-
-
toolchainが省略された場合、goディレクティブで指定したGoバージョンが代わりに使われる
原因
一言で言い切るとしたら以下です。
-
toolchainディレクティブを省略すると、代わりにgoディレクティブで指定したGoバージョンを使ってツールチェイン名を指定したことになる(toolchain 1.22)が、ツールチェイン名はパッチバージョンが省略できないのでgoコマンドがツールチェインのダウンロードに失敗する
なので、「解決方法」のようにツールチェイン名にパッチバージョンを与えると解消されます。
1.22のような省略形が言語バージョンと呼ばれることを考慮すると、今回の現象を次のように言い換えることもできます。
-
go.modにtoolchainを省略してgoディレクティブに言語バージョンを指定すると、ツールチェインのダウンロードに失敗する
仕様としてどうなの?
実はこれはバグではなく仕様です。
仕様の是非については、現在issueで突っ込まれています。
意訳すると以下のようなコメントがあります。
-
goディレクティブに言語バージョンを指定する場合は、toolchainディレクティブを指定すべきことをドキュメントに書くべきでは? - Go 1.21未満では
go 1.20.1のような記述はできなかったのに、1.21以降ではgo 1.21.0のような表記が推奨されるのはユーザーの困惑を生んでいそう
異常系としてエラーメッセージを変えてくれると嬉しいですね。
参考
-
Goツールチェインとは、標準ライブラリやコンパイラやツール等もろもろです ↩︎
Discussion