What did you do?

Clone https://github.com/opencontainers/runc/ and do this:

cd runc
ln -s / gopls-cpu-high

Then open any file in the project and wait 1-3 minutes.

For example, I used:

vim libcontainer/rootfs_linux.go

This should work with any go project that you add the symlink to.

What did you expect to see?

gopls doesn't use 2000% of cpu continously .

I'm not 100% sure gopls can handle this situation nor if it makes sense to do it. I'm mostly reporting it because it took me some hours to figure out (I had a lot of files not tracked and that symlink was a mistake). I'm fine if you want to close as won't fix :-)

What did you see instead?

gopls uses 2000% of the cpu continously.

Build info

golang.org/x/tools/gopls v0.19.1
    golang.org/x/tools/gopls@v0.19.1 h1:Yodhp3rnpnag60lVZrYPYbGMxTlTCIAj/B2Rv7AKuhA=
    github.com/BurntSushi/toml@v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
    github.com/fatih/camelcase@v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
    github.com/fatih/gomodifytags@v1.17.1-0.20250423142747-f3939df9aa3c h1:dDSgAjoOMp8da3egfz0t2S+t8RGOpEmEXZubcGuc0Bg=
    github.com/fatih/structtag@v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
    github.com/google/go-cmp@v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
    golang.org/x/exp/typeparams@v0.0.0-20250218142911-aa4b98e5adaa h1:Br3+0EZZohShrmVVc85znGpxw7Ca8hsUJlrdT/JQGw8=
    golang.org/x/mod@v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
    golang.org/x/sync@v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
    golang.org/x/telemetry@v0.0.0-20250417124945-06ef541f3fa3 h1:RXY2+rSHXvxO2Y+gKrPjYVaEoGOqh3VEXFhnWAt1Irg=
    golang.org/x/text@v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
    golang.org/x/tools@v0.34.1-0.20250610205101-c26dd3ba555e h1:XnjOegqwH6kBJoae6InSGbIFPHcLtUT/Eq8HjrZKbmQ=
    golang.org/x/vuln@v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I=
    honnef.co/go/tools@v0.7.0-0.dev.0.20250523013057-bbc2f4dd71ea h1:fj8r9irJSpolAGUdZBxJIRY3lLc4jH2Dt4lwnWyWwpw=
    mvdan.cc/gofumpt@v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU=
    mvdan.cc/xurls/v2@v2.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI=
go: go1.24.4

Comment From: adonovan

Likely a dup of https://github.com/golang/go/issues/70172. The upcoming version of gopls (which you can try out using go install golang.org/x/tools/gopls@v0.20.0-pre.1) features a new implementation of the module index which should greatly reduce the traversal of directories. Please let us know if it helps you.

Comment From: rata

@adonovan thanks! That version doesn't have any meaningful difference here (maybe instead of 2000% it uses 1900%?)

Comment From: adonovan

Hmm. Thanks for checking.

Comment From: adonovan

Thanks, I can reproduce this readily from your instructions. It is indeed a runaway file system walk in the module indexing code, as witnessed by the attached traceback.

traceback.txt


goroutine 0 gp=0x1065610a0 m=0 mp=0x106562900 [idle]:
syscall.syscall(0x140465c28f0?, 0xaf?, 0x0?, 0x0?)
    GOROOT/src/runtime/sys_darwin.go:27 +0x40 fp=0x14029234630 sp=0x140292345a0 pc=0x104d208f0
syscall.Open({0x140465c28f0?, 0x0?}, 0x1000000, 0x0)
    GOROOT/src/syscall/zsyscall_darwin_arm64.go:1162 +0x74 fp=0x14029234680 sp=0x14029234630 pc=0x104d3f214
os.open(...)
    GOROOT/src/os/file_open_unix.go:15
os.openFileNolog.func1(...)
    GOROOT/src/os/file_unix.go:262
os.ignoringEINTR(...)
    GOROOT/src/os/file_posix.go:256
os.openFileNolog({0x140465c28f0, 0xaf}, 0x0, 0x0)
    GOROOT/src/os/file_unix.go:261 +0xd4 fp=0x140292346e0 sp=0x14029234680 pc=0x104da4814
os.OpenFile({0x140465c28f0, 0xaf}, 0x0, 0x0)
    GOROOT/src/os/file.go:412 +0x40 fp=0x14029234710 sp=0x140292346e0 pc=0x104da2430
os.Open(...)
    GOROOT/src/os/file.go:390
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x140465c28f0, 0xaf}, 0x14015d50f90, {0x105d12648, 0x14038bcdf00})
    x/tools/internal/gopathwalk/walk.go:286 +0x520 fp=0x14029234840 sp=0x14029234710 pc=0x1053cb1e0
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x14046092370, 0xa7}, 0x14015d50f90, {0x105d12648, 0x14038bcc2c0})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x14029234970 sp=0x14029234840 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x14047334f00, 0xa0}, 0x14015d50f90, {0x105d12648, 0x140388c9500})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x14029234aa0 sp=0x14029234970 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x1404693bd60, 0x97}, 0x14015d50f90, {0x105d12648, 0x14038a3a5c0})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x14029234bd0 sp=0x14029234aa0 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x1404693b860, 0x94}, 0x14015d50f90, {0x105d12648, 0x14038a3a240})
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x1404693b860, 0x94}, 0x14015d50f90, {0x105d12648, 0x14038a3a240})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x14029234d00 sp=0x14029234bd0 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x14038a2f830, 0x8e}, 0x14015d50f90, {0x105d12648, 0x14038a1f8c0})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x14029234e30 sp=0x14029234d00 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x14038a17d40, 0x8c}, 0x14015d50f90, {0x105d12648, 0x14038a1ecc0})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x14029234f60 sp=0x14029234e30 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x14038a16e10, 0x81}, 0x14015d50f90, {0x105d12648, 0x1403584ca00})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x14029235090 sp=0x14029234f60 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x1403583af80, 0x7a}, 0x14015d50f90, {0x105d12648, 0x140358446c0})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x140292351c0 sp=0x14029235090 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x1403583ac00, 0x76}, 0x14015d50f90, {0x105d12648, 0x140354fe600})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x140292352f0 sp=0x140292351c0 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x140354daf00, 0x72}, 0x14015d50f90, {0x105d12648, 0x14026100100})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x14029235420 sp=0x140292352f0 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x1402589e500, 0x4a}, 0x14015d50f90, {0x105d12648, 0x140325ae280})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x14029235550 sp=0x14029235420 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x140325a8240, 0x3f}, 0x14015d50f90, {0x105d12648, 0x1403259ba80})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x14029235680 sp=0x14029235550 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x140325a8140, 0x3b}, 0x14015d50f90, {0x105d12648, 0x1403254e540})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x140292357b0 sp=0x14029235680 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x14032554200, 0x37}, 0x14015d50f90, {0x105d12648, 0x140322a9d00})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x140292358e0 sp=0x140292357b0 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x140319f7780, 0x34}, 0x14015d50f90, {0x105d12648, 0x140322a9680})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x14029235a10 sp=0x140292358e0 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x140319d3290, 0x2b}, 0x14015d50f90, {0x105d12648, 0x14019c2ea80})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x14029235b40 sp=0x14029235a10 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x140171d9350, 0x25}, 0x0, {0x105d12648, 0x140171f8a00})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x14029235c70 sp=0x14029235b40 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0x1403056f5e0, {0x140088a824f, 0x16}, 0x0, {0x105d126b8, 0x14025702e60})
    x/tools/internal/gopathwalk/walk.go:333 +0x748 fp=0x14029235da0 sp=0x14029235c70 pc=0x1053cb408
golang.org/x/tools/internal/gopathwalk.walkDir({{0x140088a824f?, 0x140133e1ed8?}, 0x140133e1ee8?}, 0x14025702e20, 0x14025702e10, {0x0?, 0xb8?, 0x1401d1c4d08?})
    x/tools/internal/gopathwalk/walk.go:121 +0x29c fp=0x14029235e80 sp=0x14029235da0 pc=0x1053ca42c
golang.org/x/tools/internal/gopathwalk.WalkSkip(...)
    x/tools/internal/gopathwalk/walk.go:78
golang.org/x/tools/internal/imports.(*ModuleResolver).scan.func4()
golang.org/x/tools/internal/imports.(*ModuleResolver).scan.func4()
    x/tools/internal/imports/mod.go:647 +0x214 fp=0x14029235fd0 sp=0x14029235e80 pc=0x1053e8c84
runtime.goexit({})
    GOROOT/src/runtime/asm_arm64.s:1268 +0x4 fp=0x14029235fd0 sp=0x14029235fd0 pc=0x104d25504
created by golang.org/x/tools/internal/imports.(*ModuleResolver).scan in goroutine 23770
    x/tools/internal/imports/mod.go:631 +0x340
...