quaint-telephone-89068
08/26/2026, 3:22 PM[golang].go_search_paths, any Pants goal that builds the Go standard library from source fails at the link step:
ProcessExecutionFailure: Process 'Link Go binary: ./package_analyzer' failed with exit code 1.
stderr:
link: sync/atomic: invalid reference to internal/runtime/atomic.Load
package_analyzer is Pants' own internal tool, so this takes down any goal that touches the Go backend — including generate-lockfiles for pure-Python resolves, if a go_mod target happens to be visible in the default build graph.
This reproduces only on amd64 (see "Why arch matters" below), which is likely why it has gone unreported: Apple Silicon dev machines build cleanly.
Root cause
Go 1.27 made two coupled changes:
1. cmd/asm gained a -std flag, and cmd/go passes it when assembling standard library packages.
• src/cmd/asm/internal/flags/flags.go (go1.27.0): Std = flag.Bool("std", false, "building standard library") — absent in go1.26.0.
• src/cmd/go/internal/work/gc.go (go1.27.0), in `asmArgs()`: if p.Standard { args = append(args, "-std") } — this block does not exist in go1.26.0.
• Introduced by golang/go@`3a0f18376fb9` ("cmd/asm, cmd/go: pass -std to assembler for standard library packages", 2026-04-02).
2. internal/runtime/atomic switched its exports from //go:linkname to the new //go:linknamestd.
• New file src/internal/runtime/atomic/linkname.go (go1.27.0) carries //go:linknamestd Load, Loadp, Load64, … In go1.26.0 these were plain //go:linkname in atomic_amd64.go.
• Introduced by golang/go@`4dde0f6c368f` ("all: use linknamestd for new linknames", 2026-05-20).
The linker then treats the two differently — src/cmd/link/internal/loader/loader.go (go1.27.0):
if osym.IsLinknameStd() {
// It is pushed with linknamestd. Allow only pulls from the
// standard library.
if refpkg.Std() {
return
}
}
if osym.IsLinkname() {
return
}
error()
refpkg.Std() reads ObjFlagStd, which is set only when the referring object was produced with -std. The reference itself lives in assembly — src/sync/atomic/asm.s (byte-identical in 1.26 and 1.27):
TEXT ·LoadUint32(SB),NOSPLIT,$0
JMP internal∕runtime∕atomic·Load(SB)
Pants passes -std to the compiler but never to the assembler. src/python/pants/backend/go/util_rules/build_pkg.py has if request.is_stdlib: compile_args.append("-std"), but src/python/pants/backend/go/util_rules/assembly.py — which builds both the -gensymabis and the assemble invocations via _asm_args(...) — contains no -std at all. So `sync/atomic`'s assembled object lacks ObjFlagStd, refpkg.Std() is false, and the link fails.
assembly.py is byte-identical across release_2.31.0, release_2.33.0 and main, so this is present on main today.
Why arch matters
• amd64: internal/runtime/atomic.Load is defined in Go (`atomic_amd64.go`: func Load(ptr *uint32) uint32 { return *ptr }), so its object comes from go tool compile, which Pants does pass -std to → the definer is std → the linker proceeds to the refpkg.Std() test, which the -std-less asm object fails → error.
• arm64: Load is defined in assembly (`atomic_arm64.s`: TEXT ·Load(SB),NOSPLIT,$0-12). checkLinkname bails out early (if !r.Std() { return }) before reaching that test, so the build succeeds.
Confirmed empirically: Pants 2.31.0 + Go 1.27.0 on darwin/arm64 builds the from-source stdlib and links package_analyzer with no error.
Reproduction
On linux/amd64, with Go 1.27.0:
PANTS_GOLANG_GO_SEARCH_PATHS='["/path/to/go1.27.0/bin"]' \
pants --no-pantsd check <any go target>
Expected: success. Actual: link: sync/atomic: invalid reference to internal/runtime/atomic.Load.
Suggested fix
Pass -std from assembly.py for stdlib packages, mirroring `build_pkg.py`'s is_stdlib handling — for both the -gensymabis and the assemble invocations. Older Go versions do not accept the flag, so it needs to be gated on the toolchain version.
Note on 2.33.0
Pants 2.33.0's [golang].use_prebuilt_stdlib_archives (default true) hides this for the common case, because it delegates to a real go install std and cmd/go passes -std itself. I verified the harvest works for linux/amd64 with Go 1.27.0 (GODEBUG=installgoroot=all go install -trimpath -pkgdir … std → 374 archives; linking a sync/atomic user against them succeeds). But per stdlib_archives.py the from-source path is still taken whenever coverage, the race detector, msan, asan, or custom compiler_flags are in play — so the underlying bug still bites in those configurations.
pantsbuild/pantsquaint-telephone-89068
08/26/2026, 3:23 PM