🚨

Go 1.25でアップデートされたpanic出力の変更内容を追ってみた

に公開

この記事は、Go Advent Calendar 2025 の 20 日目の記事です。


はじめに

Go 1.25 で panic 出力のフォーマットが変更されました。

https://tip.golang.org/doc/go1.25#change-to-unhandled-panic-output

すでに至るところで紹介されている内容かつ軽微な変更ではありますが、この記事では実際にソースコードを追いかけてみた内容を紹介します。

変更内容の確認

提案された issue はこちらです。

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

Go 1.25 以前は同じ panic が複数発生すると、以下のように出力されていました。

panic: PANIC [recovered]
  panic: PANIC

Go 1.25 以降では、以下のように出力されるようになります。

panic: PANIC [recovered, repanicked]

試してみた

issue の例を試してみます。

sample_test.go
package main

import (
	"testing"
)

func Test(t *testing.T) {
	panic("oops")
}

Go 1.24 の出力は以下のとおりです。
panic: oops が 2 回出力されています。

go1.24.0 test -v ./sample_test.go
=== RUN   Test
--- FAIL: Test (0.00s)
panic: oops [recovered]
        panic: oops

goroutine 3 [running]:
testing.tRunner.func1.2({0x1022a8620, 0x1022d79f0})
        /path/to/sdk/go1.24.0/src/testing/testing.go:1734 +0x1ac
testing.tRunner.func1()
        /path/to/sdk/go1.24.0/src/testing/testing.go:1737 +0x334
panic({0x1022a8620?, 0x1022d79f0?})
        /path/to/sdk/go1.24.0/src/runtime/panic.go:787 +0x124
command-line-arguments.Test(0x14000003500?)
        /path/to/go/src/sample/sample_test.go:8 +0x2c
testing.tRunner(0x14000003500, 0x1022d6fa8)
        /path/to/sdk/go1.24.0/src/testing/testing.go:1792 +0xe4
created by testing.(*T).Run in goroutine 1
        /path/to/sdk/go1.24.0/src/testing/testing.go:1851 +0x374
FAIL    command-line-arguments  0.619s
FAIL

報告されている通り testingパッケージの tRunner 関数内で panic を recover した後に再度 panic しているためです。

https://go.googlesource.com/go/+/refs/tags/go1.23.5/src/testing/testing.go#1632

上記コードは Go 1.25 でも同様です。

https://github.com/golang/go/blob/go1.25.0/src/testing/testing.go#L1852-L1876

変更箇所の確認

panic メッセージを作成するフローで、同じ panic が連続して発生していないかチェックするようになりました。

https://github.com/golang/go/blob/go1.25.0/src/runtime/panic.go#L636-L642

efaceOf で型情報とデータ情報を取得できるように変換して比較しています。

https://github.com/golang/go/blob/master/src/runtime/runtime2.go#L194-L196

上記の比較でrepanickedフラグが true の場合、 panic メッセージに [recovered, repanicked] を追加するようになりました。

https://github.com/golang/go/blob/go1.25.0/src/runtime/panic.go#L670-L673

試してみた

同じテストコードで確認します。

Go 1.25 の出力は以下のとおりです。
panic: oops が 1 回出力されています。repanickedで重複したログ出力が抑制されていることがわかります。

go1.25.0 test -v ./sample_test.go
=== RUN   Test
--- FAIL: Test (0.00s)
panic: oops [recovered, repanicked]

goroutine 34 [running]:
testing.tRunner.func1.2({0x100c30d20, 0x100c61710})
        /path/to/sdk/go1.25.0/src/testing/testing.go:1872 +0x190
testing.tRunner.func1()
        /path/to/sdk/go1.25.0/src/testing/testing.go:1875 +0x31c
panic({0x100c30d20?, 0x100c61710?})
        /path/to/sdk/go1.25.0/src/runtime/panic.go:783 +0x120
command-line-arguments.Test(0x14000126380?)
        /path/to/go/src/sample/sample_test.go:8 +0x2c
testing.tRunner(0x14000126380, 0x100c60c00)
        /path/to/sdk/go1.25.0/src/testing/testing.go:1934 +0xc8
created by testing.(*T).Run in goroutine 1
        /path/to/sdk/go1.25.0/src/testing/testing.go:1997 +0x364
FAIL    command-line-arguments  0.484s
FAIL

余談:reraisedからrepanickedに変更された

issue と最初の提案では[recovered, reraised] としていたのが、rsc さんからのコメントで [recovered, repanicked] に変更されました。

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

raised は例外のための用語ですが、Go には例外がないため、repanicked の方が適切という理由からです。

余談: Go 1.25 では recover されていないのに [recovered, repanicked] と表示されていた問題が修正された

ここで repanicked フラグのみチェックして、[recovered, repanicked]と表示される問題が報告されました。

https://github.com/golang/go/blob/go1.25.0/src/runtime/panic.go#L670-L673

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

現時点で確認できる Go 1.26 Release Candidate 1 で修正されていることが確認できます。

https://github.com/golang/go/blob/go1.26rc1/src/runtime/panic.go#L749-L752

おわりに

Go 1.25 で追加された panic 出力フォーマットの変更内容と、その動作を検証コードを通じて理解を深めることができました。

最後の余談の話に関しては、Go本体へのコントリビュートチャンスの余地を感じたので、引き続き気になったときにリリースノートの確認は続けていこうと思います。

Discussion