golang/go · error
internal error: unsupported COMDAT selection strategy found
Error message
internal error: unsupported COMDAT selection strategy found in path=%s sec=%d strategy=%d idx=%d, please file a bug
What it means
The Go linker encountered a COMDAT section with a selection strategy that is not supported. COMDAT sections use a selection strategy to decide how to merge duplicate definitions across object files. The Go linker only supports IMAGE_COMDAT_SELECT_ANY (pick any copy) and IMAGE_COMDAT_SELECT_SAME_SIZE (duplicates must have the same size). Other strategies such as EXACT_MATCH, ASSOCIATIVE, LARGEST, or EXPAND_POINTER are not implemented and trigger this internal error.
Source
Thrown at src/cmd/link/internal/loadpe/ldpe.go:806
if pesym.StorageClass != uint8(IMAGE_SYM_CLASS_STATIC) {
continue
}
// This symbol corresponds to a COMDAT section. Read the
// aux data for it.
auxsymp, err := state.f.COFFSymbolReadSectionDefAux(i)
if err != nil {
return fmt.Errorf("unable to read aux info for section def symbol %d %s: pe.COFFSymbolReadComdatInfo returns %v", i, symname, err)
}
if auxsymp.Selection == pe.IMAGE_COMDAT_SELECT_SAME_SIZE {
// This is supported.
} else if auxsymp.Selection == pe.IMAGE_COMDAT_SELECT_ANY {
// Also supported.
state.comdats[uint16(pesym.SectionNumber-1)] = int64(-1)
} else {
// We don't support any of the other strategies at the
// moment. I suspect that we may need to also support
// "associative", we'll see.
return fmt.Errorf("internal error: unsupported COMDAT selection strategy found in path=%s sec=%d strategy=%d idx=%d, please file a bug", state.pn, auxsymp.SecNum, auxsymp.Selection, i)
}
}
return nil
}
// LookupBaseFromImport examines the symbol "s" to see if it
// corresponds to an import symbol (name of the form "__imp_XYZ") and
// if so, it looks up the underlying target of the import symbol and
// returns it. An error is returned if the symbol is of the form
// "__imp_XYZ" but no XYZ can be found.
func LookupBaseFromImport(s loader.Sym, ldr *loader.Loader, arch *sys.Arch) (loader.Sym, error) {
sname := ldr.SymName(s)
if !strings.HasPrefix(sname, "__imp_") {
return 0, nil
}
basename := sname[len("__imp_"):]
if arch.Family == sys.I386 && basename[0] == '_' {
basename = basename[1:] // _Name => NameView on GitHub (pinned to b6b368adc5)
Solutions
- Recompile the C/C++ code with compiler flags that force simpler COMDAT strategies — e.g., with MSVC use `/Gy-` to disable function-level linking, or with Clang use `-fno-comdat-statistics` or equivalent.
- If using C++, consider rewriting the problematic code in C (which rarely uses COMDAT) or isolating it into a precompiled static library that Go links against rather than compiling directly.
- Update Go to the latest version — newer releases may add support for additional COMDAT strategies (check release notes and the Go issue tracker).
- File a bug at https://go.dev/issue including the strategy number from the error message and the object file, as the source comment explicitly requests ('please file a bug').
- As a workaround, use `-ldflags=-linkmode=external` to delegate linking to an external linker (gcc/ld) that handles all COMDAT strategies natively.
Example fix
# Use external linker mode to bypass Go's internal COMDAT limitations go build -ldflags='-linkmode=external' ./... # Or recompile C code to avoid aggressive COMDAT strategies # With Clang: clang -c -fmerge-all-constants file.c -o file.o
Defensive patterns
Strategy: fallback
Prevention
- When linking C++ via cgo on Windows, prefer -ldflags=-linkmode=external to let the system linker handle complex COMDAT strategies.
- Avoid C++ templates and inline functions in cgo boundary code — they generate complex COMDAT sections.
- Keep C/C++ interop code simple: prefer plain C with standard function definitions.
- Test cgo builds with different compiler optimization levels; -O0 may produce simpler COMDAT sections.
When it happens
Trigger: Fires in `preprocessSymbols` at ldpe.go:802-806 when the auxiliary symbol record's `Selection` field is neither IMAGE_COMDAT_SELECT_SAME_SIZE nor IMAGE_COMDAT_SELECT_ANY. This is the code path reached only after successfully reading the aux record (past the check at line 794). The comment in source explicitly notes that 'associative' strategy may need future support.
Common situations: Linking C++ code via cgo on Windows that uses template instantiations or inline functions placed in COMDAT sections with EXACT_MATCH or LARGEST strategies. Using LLVM/Clang-produced object files that default to stricter COMDAT strategies than MSVC. C++ libraries with `__declspec(selectany)` or similar that compile to non-ANY/non-SAME_SIZE COMDAT. Debug builds of C code that emit COMDAT sections for incremental linking features.
Related errors
- unable to read aux info for section def symbol %d %s: pe.COF
- %s: invalid symbol binding %d
- internal error: import symbol %q with no underlying sym
- internal error in windynrelocsym: redirect GOT token applied
- internal error in windynrelocsym: underlying sym for %q has
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/3611cb50bad389e7.
Report an issue: GitHub.