📑

go.modのgoディレクティブにパッチバージョンを含めないと「toolchain not available」と怒られる

2024/03/17に公開

(2024.4.20 追記)
注意: 将来のGoでは、パッチバージョンを含めなくてもエラーが出なくなる修正が検討されています。

Go 1.21, 1.22で同様のエラーが出る方は、本記事を参考に解決できます。

現象

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.modgoディレクティブに指定する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というツールチェインでビルドすることを許しません。

ここで以下に注意してください。

  1. gotoolchainディレクティブの違い
    • goディレクティブはGoバージョンを指定する。例: 1.22.0,1.22,1.22rc1
    • toolchainディレクティブはGoツールチェイン名を指定する。例: go1.22.0
  2. toolchainが省略された場合、goディレクティブで指定したGoバージョンが代わりに使われる

原因

一言で言い切るとしたら以下です。

  • toolchainディレクティブを省略すると、代わりにgoディレクティブで指定したGoバージョンを使ってツールチェイン名を指定したことになる(toolchain 1.22)が、ツールチェイン名はパッチバージョンが省略できないのでgoコマンドがツールチェインのダウンロードに失敗する

なので、「解決方法」のようにツールチェイン名にパッチバージョンを与えると解消されます。

1.22のような省略形が言語バージョンと呼ばれることを考慮すると、今回の現象を次のように言い換えることもできます。

  • go.modtoolchainを省略してgoディレクティブに言語バージョンを指定すると、ツールチェインのダウンロードに失敗する

仕様としてどうなの?

実はこれはバグではなく仕様です。

仕様の是非については、現在issueで突っ込まれています。

https://github.com/golang/go/issues/62278

意訳すると以下のようなコメントがあります。

  • goディレクティブに言語バージョンを指定する場合は、toolchainディレクティブを指定すべきことをドキュメントに書くべきでは?
  • Go 1.21未満ではgo 1.20.1のような記述はできなかったのに、1.21以降ではgo 1.21.0のような表記が推奨されるのはユーザーの困惑を生んでいそう

異常系としてエラーメッセージを変えてくれると嬉しいですね。

参考

脚注
  1. Goツールチェインとは、標準ライブラリやコンパイラやツール等もろもろです ↩︎

Discussion