golang/go · error
%s: invalid symbol binding %d
Error message
%s: invalid symbol binding %d
What it means
The Go linker's PE (Windows) object loader encountered a COFF symbol whose StorageClass value does not match any of the recognized classes (IMAGE_SYM_CLASS_EXTERNAL, IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL). The symbol's storage class determines how it is bound during linking; an unrecognized class means the linker cannot decide whether to treat it as a global, local, or label symbol. This error surfaces the raw numeric storage class value so the offending symbol and its provenance can be identified.
Source
Thrown at src/cmd/link/internal/loadpe/ldpe.go:745
// Microsoft's PE documentation is contradictory. It says that the symbol's complex type
// is stored in the pesym.Type most significant byte, but MSVC, LLVM, and mingw store it
// in the 4 high bits of the less significant byte.
switch uint8(pesym.Type&0xf0) >> 4 {
default:
return nil, 0, fmt.Errorf("%s: invalid symbol type %d", symname, pesym.Type)
case IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_NULL:
switch pesym.StorageClass {
case IMAGE_SYM_CLASS_EXTERNAL: //global
s = state.l.LookupOrCreateCgoExport(name, 0)
case IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL:
s = state.l.LookupOrCreateCgoExport(name, state.localSymVersion)
bld = makeUpdater(state.l, bld, s)
bld.SetDuplicateOK(true)
default:
return nil, 0, fmt.Errorf("%s: invalid symbol binding %d", symname, pesym.StorageClass)
}
}
if s != 0 && state.l.SymType(s) == 0 && (pesym.StorageClass != IMAGE_SYM_CLASS_STATIC || pesym.Value != 0) {
bld = makeUpdater(state.l, bld, s)
bld.SetType(sym.SXREF)
}
return bld, s, nil
}
// preprocessSymbols walks the COFF symbols for the PE file we're
// reading and looks for cases where we have both a symbol definition
// for "XXX" and an "__imp_XXX" symbol, recording these cases in a map
// in the state struct. This information will be used in readpesym()
// above to give such symbols special treatment. This function also
// gathers information about COMDAT sections/symbols for later use
// in readpesym().View on GitHub (pinned to b6b368adc5)
Solutions
- Inspect the exact storage class number in the error output and cross-reference it with the PE/COFF IMAGE_SYM_CLASS_* constants in debug/pe to understand what symbol type is being emitted.
- Update to the latest Go release — support for additional storage classes is added over time; check the Go issue tracker for your specific storage class value.
- Recompile the offending C/object file with a different toolchain (e.g., switch between MSVC and MinGW-w64, or update to a newer compiler version) to emit standard storage classes.
- File a bug at https://go.dev/issue with the object file, the symbol name, and the storage class value so the linker can be extended to handle it.
- If you control the C source, mark symbols explicitly as `extern` (IMAGE_SYM_CLASS_EXTERNAL) or `static` (IMAGE_SYM_CLASS_STATIC) to force a recognized storage class.
Example fix
// C source: ensure symbols use standard storage classes
// before (weak symbol — may emit IMAGE_SYM_CLASS_WEAK_EXTERNAL):
__attribute__((weak)) int my_symbol(void) { return 0; }
// after (force a recognized storage class):
int my_symbol(void) { return 0; } Defensive patterns
Strategy: validation
Validate before calling
// Before linking, inspect object files for unsupported storage classes // This is a linker-internal check; end users validate by inspecting .obj files // Use dumpbin (MSVC) or objdump (MinGW) to review symbol storage classes: // dumpbin /symbols file.obj // objdump -t file.obj // Look for storage class values outside EXTERNAL(2), NULL(3), STATIC(3), LABEL(6)
Type guard
// Not applicable — this is an internal linker error with no runtime API surface. // The PE loader is invoked during go build/link, not callable by user code.
Prevention
- Keep your C compiler updated to a version known to produce Go-linker-compatible COFF symbols.
- When using cgo on Windows, prefer standard symbol declarations (extern/static) over compiler-specific extensions like weak symbols.
- Test cgo builds after updating your C compiler toolchain — new compiler versions may introduce new storage classes.
- Use -ldflags=-linkmode=external to delegate to the system linker if the internal linker rejects symbols.
When it happens
Trigger: Triggered during `readpesym` when processing a COFF symbol from a PE/COFF object file (typically a .obj or .o produced by an external C/C++ compiler via cgo on Windows). The switch on `pesym.StorageClass` at ldpe.go:735 falls through to the default branch. The symbol's type field bits 4-7 must be FUNCTION or NULL (checked at ldpe.go:730), so this only fires for symbols with a valid complex type but an unsupported storage class.
Common situations: Using cgo on Windows with a C compiler that emits unusual COFF storage classes (e.g., IMAGE_SYM_CLASS_WEAK_EXTERNAL, IMAGE_SYM_CLASS_SECTION, IMAGE_SYM_CLASS_EXTERNAL_DEF). Mixing object files from non-standard toolchains (LLVM/Clang variants, older MSVC, or unusual MinGW builds). Corrupt or truncated object files where the storage class byte is garbage. Upgrading a C compiler that starts emitting symbols the Go linker hasn't been taught to handle.
Related errors
- unable to read aux info for section def symbol %d %s: pe.COF
- internal error: unsupported COMDAT selection strategy found
- could not map %s symbol with no section
- could not map %s symbol with non .text or .rdata or .data se
- internal error: import symbol %q with no underlying sym
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/a1bcb93631a9d954.
Report an issue: GitHub.