golang/go · error

case-insensitive file name collision: %q and %q

Error message

case-insensitive file name collision: %q and %q

What it means

A package contains two input files whose names differ only by letter case (e.g., Foo.go and foo.go). The Go toolchain rejects this because case-insensitive filesystems (macOS APFS/HFS+ in default config, Windows NTFS) would treat them as the same file, causing unpredictable build behavior. The str.FoldDup function compares all file names from p.AllFiles() using Unicode case-folding.

Source

Thrown at src/cmd/go/internal/load/pkg.go:2030

	if !opts.SuppressEmbedFiles {
		p.EmbedFiles, p.Internal.Embed, err = resolveEmbed(p.Dir, p.EmbedPatterns)
		if err != nil {
			p.Incomplete = true
			setError(err)
			embedErr := err.(*EmbedError)
			p.Error.setPos(p.Internal.Build.EmbedPatternPos[embedErr.Pattern])
		}
	}

	// Check for case-insensitive collision of input files.
	// To avoid problems on case-insensitive files, we reject any package
	// where two different input files have equal names under a case-insensitive
	// comparison.
	inputs := p.AllFiles()
	f1, f2 := str.FoldDup(inputs)
	if f1 != "" {
		setError(fmt.Errorf("case-insensitive file name collision: %q and %q", f1, f2))
		return
	}

	// If first letter of input file is ASCII, it must be alphanumeric.
	// This avoids files turning into flags when invoking commands,
	// and other problems we haven't thought of yet.
	// Also, _cgo_ files must be generated by us, not supplied.
	// They are allowed to have //go:cgo_ldflag directives.
	// The directory scan ignores files beginning with _,
	// so we shouldn't see any _cgo_ files anyway, but just be safe.
	for _, file := range inputs {
		if !SafeArg(file) || strings.HasPrefix(file, "_cgo_") {
			setError(fmt.Errorf("invalid input file name %q", file))
			return
		}
	}
	if name := pathpkg.Base(p.ImportPath); !SafeArg(name) {
		setError(fmt.Errorf("invalid input directory name %q", name))

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Rename one of the colliding files to a distinctly different name.
  2. If the collision involves generated files (e.g., cgo outputs), check cgo directives and source file naming.
  3. Add a case-collision check to CI on case-sensitive systems (Linux) to catch issues before they reach macOS/Windows developers.
  4. Run go list -f '{{.GoFiles}} {{.CgoFiles}} {{.AllFiles}}' . to enumerate all input files.

Example fix

# before — case-only difference
mv Foo.go foo.go  # both Foo.go and foo.go exist
# after — distinct names
git mv foo.go foo_impl.go
Defensive patterns

Strategy: validation

Validate before calling

// Check for case-insensitive filename collisions in a directory.
func checkCaseCollisions(dir string) error {
    entries, err := os.ReadDir(dir)
    if err != nil {
        return err
    }
    seen := make(map[string]string)
    for _, e := range entries {
        folded := strings.ToLower(e.Name())
        if orig, ok := seen[folded]; ok {
            return fmt.Errorf("case collision: %q and %q", orig, e.Name())
        }
        seen[folded] = e.Name()
    }
    return nil
}

Prevention

When it happens

Trigger: Two files in the same package directory with names that are equal under strings.EqualFold (Unicode case-insensitive comparison). FoldDup iterates the sorted list and returns the first colliding pair. p.AllFiles() includes Go files, C files, assembly files, and any other inputs — not just .go files.

Common situations: Developing on Linux (case-sensitive) but targeting macOS or Windows (case-insensitive). Git merges or file renames that accidentally create case-only differences. Files generated by different tools (cgo, protoc, etc.) that produce names differing only in case. Filesystem migrations between case-sensitive and case-insensitive volumes.

Related errors


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