Skip to content
Latchkey

Go CGO_ENABLED=0 Static Build Failures - Fix in CI

Building with CGO_ENABLED=0 produces a fully static binary that runs on scratch/distroless images. It fails when a dependency genuinely needs cgo, and it can silently produce a dynamically linked binary when cgo is left on, breaking the minimal-image deploy you were aiming for.

What this error means

A CGO_ENABLED=0 go build fails because a package requires cgo, or the build succeeds but the resulting binary crashes on a scratch image with no such file or directory (a missing dynamic loader) because cgo was actually enabled.

go build output
# building for a scratch image with cgo off:
# github.com/mattn/go-sqlite3
cgo: C source files not allowed when not using cgo
# or, cgo left on, the static-looking binary fails at runtime on scratch:
exec /app: no such file or directory

Common causes

A dependency requires cgo

A package (a cgo SQLite driver, some DNS/user-lookup paths) only builds with cgo, so disabling it breaks the build.

cgo left enabled for a "static" build

Without CGO_ENABLED=0, the default on most images links against libc dynamically, so the binary is not static and fails on scratch/distroless.

How to fix it

Build static and pure-Go

Disable cgo and use the pure-Go resolvers so the binary has no dynamic dependencies.

Terminal
CGO_ENABLED=0 GOOS=linux go build -tags netgo -ldflags '-extldflags "-static"' ./cmd/app

Swap a cgo dependency for a pure-Go one

  1. Find the package that requires cgo (build with -x to see the gcc call).
  2. Replace it with a pure-Go equivalent (e.g. a non-cgo SQLite driver).
  3. Re-run CGO_ENABLED=0 go build to confirm it now builds static.

Verify the binary is actually static

Terminal
CGO_ENABLED=0 go build -o app ./cmd/app
file app        # should say "statically linked"
ldd app || true # "not a dynamic executable" confirms static

How to prevent it

  • Set CGO_ENABLED=0 explicitly for scratch/distroless deploys.
  • Prefer pure-Go dependencies so static builds always work.
  • Verify with file/ldd that release binaries are truly static.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →