golang/go · error
%s requires external (cgo) linking, but cgo is not enabled
Error message
%s requires external (cgo) linking, but cgo is not enabled
What it means
Returned by LinkerDeps at line 2687. externalLinkingReason (line 2714) decides the final binary must use external (cgo) linking — because the target platform always requires it (platform.MustLinkExternal, e.g. some os/arch combos), because of -buildmode=c-shared/plugin, because of -linkshared, because PIE on a platform without internal-link PIE support, or because -ldflags=-linkmode=external was passed. If cgo is then disabled (cfg.BuildContext.CgoEnabled false, and compiler != gccgo), runtime/cgo cannot be pulled in and the build aborts. gccgo is exempt because it links externally natively.
Source
Thrown at src/cmd/go/internal/load/pkg.go:2683
// We accept leading . _ and / as likely in file system paths.
// There is a copy of this function in cmd/compile/internal/noder/noder.go.
func SafeArg(name string) bool {
if name == "" {
return false
}
c := name[0]
return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '.' || c == '_' || c == '/' || c >= utf8.RuneSelf
}
// LinkerDeps returns the list of linker-induced dependencies for main package p.
func LinkerDeps(s *modload.Loader, p *Package) ([]string, error) {
// Everything links runtime.
deps := []string{"runtime"}
// External linking mode forces an import of runtime/cgo.
if what := externalLinkingReason(s, p); what != "" && cfg.BuildContext.Compiler != "gccgo" {
if !cfg.BuildContext.CgoEnabled {
return nil, fmt.Errorf("%s requires external (cgo) linking, but cgo is not enabled", what)
}
deps = append(deps, "runtime/cgo")
}
// On ARM with GOARM=5, it forces an import of math, for soft floating point.
if cfg.Goarch == "arm" {
deps = append(deps, "math")
}
// Using the race detector forces an import of runtime/race.
if cfg.BuildRace {
deps = append(deps, "runtime/race")
}
// Using memory sanitizer forces an import of runtime/msan.
if cfg.BuildMSan {
deps = append(deps, "runtime/msan")
}
// Using address sanitizer forces an import of runtime/asan.
if cfg.BuildASan {
deps = append(deps, "runtime/asan")View on GitHub (pinned to b6b368adc5)
Solutions
- Enable cgo: set CGO_ENABLED=1 and ensure a C compiler (gcc/clang) is on PATH for the target.
- Remove the constraint that forces external linking: drop -buildmode=c-shared/plugin/pie, drop -linkshared, or drop -ldflags=-linkmode=external.
- If you must ship a static binary, switch to a target/platform that supports internal linking and drop the external-linking buildmode.
- On gccgo the check is skipped, but switching compiler is rarely the right fix — prefer enabling cgo.
Example fix
# before CGO_ENABLED=0 go build -buildmode=pie ./cmd/app # after CGO_ENABLED=1 go build -buildmode=pie ./cmd/app # or drop -buildmode=pie
Defensive patterns
Strategy: validation
Validate before calling
// Detect the conflict up front: if any external-linking-forcing flag is set,
// CGO must be enabled. Mirror externalLinkingReason's decision inputs.
package buildcheck
import (
"errors"
"os"
"strings"
)
// platforms that always require external linking; consult cmd/go's
// platform.MustLinkExternal for the authoritative list.
var mustLinkExternal = map[string]bool{
"android/arm": true, // etc.
}
func CgoCompatibleWithFlags(goos, goarch, buildmode, ldflags string) error {
cgoEnabled := os.Getenv("CGO_ENABLED") != "0"
forcesExternal := false
switch buildmode {
case "c-shared", "plugin":
forcesExternal = true
case "pie":
forcesExternal = true // conservative; depends on InternalLinkPIESupported
}
if strings.Contains(ldflags, "-linkmode=external") {
forcesExternal = true
}
if mustLinkExternal[goos+"/"+goarch] {
forcesExternal = true
}
if forcesExternal && !cgoEnabled {
return errors.New("selected build flags require external (cgo) linking; set CGO_ENABLED=1")
}
return nil
} Try / catch
// If a scripted build fails with this message, retry with cgo enabled:
//
// cmd := exec.Command("go", "build", flags...)
// if out, err := cmd.CombinedOutput(); err != nil &&
// bytes.Contains(out, []byte("requires external (cgo) linking")) {
// cmd = exec.Command("go", append([]string{"env", "-w", "CGO_ENABLED=1"})...)
// _ = cmd.Run()
// } Prevention
- Never combine `CGO_ENABLED=0` with `-buildmode=pie/c-shared/plugin` or `-linkshared` without verifying the platform supports internal linking.
- In Dockerfiles, set CGO_ENABLED explicitly and document why — silent defaults cause this collision.
When it happens
Trigger: Building with CGO_ENABLED=0 while any of: targeting a platform in platform.MustLinkExternal; -buildmode=c-shared or -plugin (non-wasm); -linkshared; -buildmode=pie on a platform lacking InternalLinkPIESupported; or -ldflags=-linkmode=external.
Common situations: Docker `CGO_ENABLED=0` scratch images combined with `-buildmode=pie` or `-buildmode=c-shared`; cross-compiling to darwin/arm64 or android with cgo off; CI hardening setting PIE defaults while forcing static binaries; passing -linkshared without a cgo-enabled toolchain.
Related errors
- C compiler %q not found: %v
- Fortran source files not allowed when not using cgo or SWIG:
- main package is in repository %q but current directory is in
- main module is in repository %q but current directory is in
- named files must be .go files: %s
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/452e01a126629d74.
Report an issue: GitHub.