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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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

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


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/a1bcb93631a9d954. Report an issue: GitHub.