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 => Name

View on GitHub (pinned to b6b368adc5)

Solutions

  1. 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.
  2. 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.
  3. Update Go to the latest version — newer releases may add support for additional COMDAT strategies (check release notes and the Go issue tracker).
  4. 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').
  5. 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 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


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