Skip to content

Conversation

@adlternative
Copy link
Contributor

@adlternative adlternative commented Dec 2, 2025

I encountered an issue during the process of integrating zoekt with gitea go-gitea/gitea#33850:

runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0x14025a6e350 stack=[0x14025a6e000, 0x14045a6e000]
fatal error: stack overflow

runtime stack:
runtime.throw({0x1055f3893?, 0x103019b20?})
        /Users/adl/sdk/go1.25.4/src/runtime/panic.go:1094 +0x34 fp=0x16cf2ada0 sp=0x16cf2ad70 pc=0x103062f14
runtime.newstack()
        /Users/adl/sdk/go1.25.4/src/runtime/stack.go:1159 +0x44c fp=0x16cf2aed0 sp=0x16cf2ada0 pc=0x103047b0c
runtime.morestack()
        /Users/adl/sdk/go1.25.4/src/runtime/asm_arm64.s:392 +0x70 fp=0x16cf2aed0 sp=0x16cf2aed0 pc=0x103069350

goroutine 659 gp=0x14002e79dc0 m=2 mp=0x1400009a808 [running]:
encoding/json/jsontext.(*decoderState).consumeValue(0x140152fb2c0, 0x14025a6e710, 0x60?, 0x4)
        /Users/adl/sdk/go1.25.4/src/encoding/json/jsontext/decode.go:835 +0x544 fp=0x14025a6e350 sp=0x14025a6e350 pc=0x1031e7f04
encoding/json/jsontext.(*decoderState).consumeObject(0x140152fb2c0, 0x14025a6e710, 0x14025a6e4c8?, 0x3)
        /Users/adl/sdk/go1.25.4/src/encoding/json/jsontext/decode.go:1026 +0x65c fp=0x14025a6e440 sp=0x14025a6e350 pc=0x1031e89cc
encoding/json/jsontext.(*decoderState).consumeValue(0x140152fb2c0, 0x14025a6e710, 0x14025a6e5b8?, 0x3)
        /Users/adl/sdk/go1.25.4/src/encoding/json/jsontext/decode.go:863 +0x3c4 fp=0x14025a6e4b0 sp=0x14025a6e440 pc=0x1031e7d84
encoding/json/jsontext.(*decoderState).consumeArray(0x140152fb2c0, 0x14025a6e710, 0x0?, 0x0?)
        /Users/adl/sdk/go1.25.4/src/encoding/json/jsontext/decode.go:1084 +0x1b8 fp=0x14025a6e500 sp=0x14025a6e4b0 pc=0x1031e9198
encoding/json/jsontext.(*decoderState).consumeValue(0x140152fb2c0, 0x14025a6e710, 0x14025a6e678?, 0x2)
        /Users/adl/sdk/go1.25.4/src/encoding/json/jsontext/decode.go:865 +0x32c fp=0x14025a6e570 sp=0x14025a6e500 pc=0x1031e7cec
encoding/json/jsontext.(*decoderState).consumeObject(0x140152fb2c0, 0x14025a6e710, 0x14025a6e798?, 0x1)
        /Users/adl/sdk/go1.25.4/src/encoding/json/jsontext/decode.go:1026 +0x65c fp=0x14025a6e660 sp=0x14025a6e570 pc=0x1031e89cc
encoding/json/jsontext.(*decoderState).consumeValue(0x140152fb2c0, 0x14025a6e710, 0x0?, 0x1)
        /Users/adl/sdk/go1.25.4/src/encoding/json/jsontext/decode.go:863 +0x3c4 fp=0x14025a6e6d0 sp=0x14025a6e660 pc=0x1031e7d84
encoding/json/jsontext.(*decoderState).CheckNextValue(0x140152fb2c0)
        /Users/adl/sdk/go1.25.4/src/encoding/json/jsontext/decode.go:781 +0x64 fp=0x14025a6e720 sp=0x14025a6e6d0 pc=0x1031e7724
encoding/json/v2.unmarshalDecode(0x140152fb2c0, {0x106383fe0?, 0x1400029d4a0?}, 0x140152fb380)
        /Users/adl/sdk/go1.25.4/src/encoding/json/v2/arshal.go:484 +0x114 fp=0x14025a6e7b0 sp=0x14025a6e720 pc=0x103200794
encoding/json/v2.unmarshalFull(0x140152fb2c0, {0x106383fe0?, 0x1400029d4a0?}, 0x14025a6e8c8?)
        /Users/adl/sdk/go1.25.4/src/encoding/json/v2/arshal.go:437 +0x28 fp=0x14025a6e800 sp=0x14025a6e7b0 pc=0x103200588
encoding/json/v2.Unmarshal({0x12f9d5750?, 0x16d?, 0x14025a6e8d8?}, {0x106383fe0, 0x1400029d4a0}, {0x14025a6e8c8?, 0x197?, 0x1031e7cec?})
        /Users/adl/sdk/go1.25.4/src/encoding/json/v2/arshal.go:412 +0x80 fp=0x14025a6e880 sp=0x14025a6e800 pc=0x103200290
encoding/json.Unmarshal(...)
        /Users/adl/sdk/go1.25.4/src/encoding/json/v2_decode.go:98
github.com/sourcegraph/zoekt.(*Repository).UnmarshalJSON(0x1400029d4a0, {0x12f9d5750?, 0x140152fb180?, 0x14025a6e9a0?})
        /Users/adl/go/pkg/mod/github.com/sourcegraph/[email protected]/api.go:656 +0x60 fp=0x14025a6e8e0 sp=0x14025a6e880 pc=0x1047da750
encoding/json/v2.makeMethodArshaler.func6(0x140152fb180, {{0x1069ed0a0?, 0x1400029d4a0?, 0x0?}, 0x50?}, 0x140152fb240)
        /Users/adl/sdk/go1.25.4/src/encoding/json/v2/arshal_methods.go:264 +0x148 fp=0x14025a6e9b0 sp=0x14025a6e8e0 pc=0x1032108a8
encoding/json/v2.unmarshalDecode(0x140152fb180, {0x106383fe0?, 0x1400029d4a0?}, 0x140152fb240)
        /Users/adl/sdk/go1.25.4/src/encoding/json/v2/arshal.go:494 +0x18c fp=0x14025a6ea40 sp=0x14025a6e9b0 pc=0x10320080c
encoding/json/v2.unmarshalFull(0x140152fb180, {0x106383fe0?, 0x1400029d4a0?}, 0x14025a6eb58?)
        /Users/adl/sdk/go1.25.4/src/encoding/json/v2/arshal.go:437 +0x28 fp=0x14025a6ea90 sp=0x14025a6ea40 pc=0x103200588
encoding/json/v2.Unmarshal({0x12f9d5750?, 0x16d?, 0x14025a6eb68?}, {0x106383fe0, 0x1400029d4a0}, {0x14025a6eb58?, 0x197?, 0x1031e7cec?})
        /Users/adl/sdk/go1.25.4/src/encoding/json/v2/arshal.go:412 +0x80 fp=0x14025a6eb10 sp=0x14025a6ea90 pc=0x103200290

Then I discovered that it was because the encoding/json jsonv2 enabled in gitea has a bug:
golang/go#75361

In short, jsonv2 causes an infinite loop when declaring a new type in a struct's UnmarshalJSON() method and then unmarshaling this new type, while jsonv1 avoids this issue by default, resulting in incompatibility between v1/v2.

Therefore, currently the simplest fix is to define type repository Repository instead of type repository *Repository in the Repository's UnmarshalJSON method to avoid infinite loop stack overflow.

How to reproduce this bug, use original code and

cd /zoekt && GOEXPERIMENT=jsonv2 go test -tags=jsonv2 -run TestRepositoryUnmarshalJSONStackOverflowFix  -v
=== RUN   TestRepositoryUnmarshalJSONStackOverflowFix
runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0x14020f90390 stack=[0x14020f90000, 0x14040f90000]
fatal error: stack overflow

runtime stack:
runtime.throw({0x100ccf716?, 0x100698c30?})
        /Users/adl/sdk/go1.25.4/src/runtime/panic.go:1094 +0x34 fp=0x16fd96da0 sp=0x16fd96d70 pc=0x1006e12b4
runtime.newstack()
        /Users/adl/sdk/go1.25.4/src/runtime/stack.go:1159 +0x44c fp=0x16fd96ed0 sp=0x16fd96da0 pc=0x1006c65fc
...

This fixes a bug caused by jsonv2 json.Unmarshal() behavior that is not backward compatible.
The infinite recursion occurs when UnmarshalJSON calls json.Unmarshal on itself.

See: golang/go#75361
Copy link
Member

@keegancsmith keegancsmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@keegancsmith keegancsmith merged commit 886b229 into sourcegraph:main Dec 2, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants