golang/go · error
flag %q triggers external linking
Error message
flag %q triggers external linking
What it means
Thrown by checkCompilerFlagsForInternalLink when a compiler flag begins with `-flto` (link-time optimization) while the build is attempting internal (Go-only) linking. LTO embeds IR that only the external system linker can resolve, so the go command refuses it rather than silently falling back.
Source
Thrown at src/cmd/go/internal/work/security.go:339
return checkFlags(name, source, list, nil, validPkgConfigFlags, nil, checkOverrides)
}
// checkCompilerFlagsForInternalLink returns an error if 'list'
// contains a flag or flags that may not be fully supported by
// internal linking (meaning that we should punt the link to the
// external linker).
func checkCompilerFlagsForInternalLink(name, source string, list []string) error {
checkOverrides := false
if err := checkFlags(name, source, list, nil, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides); err != nil {
return err
}
// Currently the only flag on the allow list that causes problems
// for the linker is "-flto"; check for it manually here.
// Also check for -static/--static, which some toolchains accept
// as a compiler flag.
for _, fl := range list {
if strings.HasPrefix(fl, "-flto") {
return fmt.Errorf("flag %q triggers external linking", fl)
}
if fl == "-static" || fl == "--static" {
return fmt.Errorf("flag %q triggers external linking", fl)
}
}
return nil
}
// checkLinkerFlagsForInternalLink returns an error if 'list'
// contains linker flags that are not compatible with internal linking.
func checkLinkerFlagsForInternalLink(name, source string, list []string) error {
checkOverrides := false
if err := checkFlags(name, source, list, nil, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides); err != nil {
return err
}
// Flags that force static linking require the external linker
// to resolve libc symbols. See #77768.
for _, fl := range list {View on GitHub (pinned to b6b368adc5)
Solutions
- Remove `-flto` from CGO_CFLAGS / the #cgo CFLAGS line and rebuild.
- Allow external linking: add `-buildmode=pie` or build with cgo so the external linker is used (the flag is only blocked for internal linking).
- Override the inherited CFLAGS: `CGO_CFLAGS='' go build`.
- Find the source: `go build -x` prints the offending flag and which #cgo block contributed it.
Example fix
// before // #cgo CFLAGS: -O2 -flto // after // #cgo CFLAGS: -O2
Defensive patterns
Strategy: validation
Validate before calling
// Strip -flto* from CGO_CFLAGS before building
cflags := os.Getenv("CGO_CFLAGS")
filtered := cflags[:0]
for _, f := range strings.Fields(cflags) {
if !strings.HasPrefix(f, "-flto") {
filtered = append(filtered, f)
}
}
os.Setenv("CGO_CFLAGS", strings.Join(filtered, " ")) Prevention
- Avoid exporting CFLAGS=-flto globally in CI.
- Audit #cgo CFLAGS lines in vendored C deps.
- Prefer per-package CGO_CFLAGS over inherited env.
When it happens
Trigger: Build a pure-Go or cgo package with internal linking while CGO_CFLAGS / CGO_LDFLAGS / a #cgo CFLAGS line contains `-flto`, `-flto=auto`, `-flto=thin`, etc. The HasPrefix("-flto") branch in checkCompilerFlagsForInternalLink returns.
Common situations: Inheriting distro CFLAGS (`export CFLAGS=-flto`) that bleed into CGO_CFLAGS; a vendored C dependency that hard-codes `-flto` in its #cgo directive; CI that sets aggressive optimization env vars globally.
Related errors
- parsing $CGO_%s_ALLOW: %v
- parsing $CGO_%s_DISALLOW: %v
- invalid flag in %s: %s %s (see https://go.dev/s/invalidflag)
- invalid flag in %s: %s without argument (see https://go.dev/
- invalid flag in %s: %s (see https://go.dev/s/invalidflag)
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/e9a9ea6a1d140b89.
Report an issue: GitHub.