{"record":{"id":"b29b95c569098c6b","repo":"golang/go","slug":"case-insensitive-file-name-collision-q-and-q","errorCode":null,"errorMessage":"case-insensitive file name collision: %q and %q","messagePattern":"case-insensitive file name collision: %q and %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/load/pkg.go","lineNumber":2030,"sourceCode":"\n\tif !opts.SuppressEmbedFiles {\n\t\tp.EmbedFiles, p.Internal.Embed, err = resolveEmbed(p.Dir, p.EmbedPatterns)\n\t\tif err != nil {\n\t\t\tp.Incomplete = true\n\t\t\tsetError(err)\n\t\t\tembedErr := err.(*EmbedError)\n\t\t\tp.Error.setPos(p.Internal.Build.EmbedPatternPos[embedErr.Pattern])\n\t\t}\n\t}\n\n\t// Check for case-insensitive collision of input files.\n\t// To avoid problems on case-insensitive files, we reject any package\n\t// where two different input files have equal names under a case-insensitive\n\t// comparison.\n\tinputs := p.AllFiles()\n\tf1, f2 := str.FoldDup(inputs)\n\tif f1 != \"\" {\n\t\tsetError(fmt.Errorf(\"case-insensitive file name collision: %q and %q\", f1, f2))\n\t\treturn\n\t}\n\n\t// If first letter of input file is ASCII, it must be alphanumeric.\n\t// This avoids files turning into flags when invoking commands,\n\t// and other problems we haven't thought of yet.\n\t// Also, _cgo_ files must be generated by us, not supplied.\n\t// They are allowed to have //go:cgo_ldflag directives.\n\t// The directory scan ignores files beginning with _,\n\t// so we shouldn't see any _cgo_ files anyway, but just be safe.\n\tfor _, file := range inputs {\n\t\tif !SafeArg(file) || strings.HasPrefix(file, \"_cgo_\") {\n\t\t\tsetError(fmt.Errorf(\"invalid input file name %q\", file))\n\t\t\treturn\n\t\t}\n\t}\n\tif name := pathpkg.Base(p.ImportPath); !SafeArg(name) {\n\t\tsetError(fmt.Errorf(\"invalid input directory name %q\", name))","sourceCodeStart":2012,"sourceCodeEnd":2048,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/load/pkg.go#L2012-L2048","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rename one of the colliding files to a distinctly different name.","If the collision involves generated files (e.g., cgo outputs), check cgo directives and source file naming.","Add a case-collision check to CI on case-sensitive systems (Linux) to catch issues before they reach macOS/Windows developers.","Run go list -f '{{.GoFiles}} {{.CgoFiles}} {{.AllFiles}}' . to enumerate all input files."],"exampleFix":"# before — case-only difference\nmv Foo.go foo.go  # both Foo.go and foo.go exist\n# after — distinct names\ngit mv foo.go foo_impl.go","handlingStrategy":"validation","validationCode":"// Check for case-insensitive filename collisions in a directory.\nfunc checkCaseCollisions(dir string) error {\n    entries, err := os.ReadDir(dir)\n    if err != nil {\n        return err\n    }\n    seen := make(map[string]string)\n    for _, e := range entries {\n        folded := strings.ToLower(e.Name())\n        if orig, ok := seen[folded]; ok {\n            return fmt.Errorf(\"case collision: %q and %q\", orig, e.Name())\n        }\n        seen[folded] = e.Name()\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run a case-collision check in CI on Linux before deploying to macOS/Windows.","Use consistent casing conventions for all filenames (e.g., lowercase_with_underscores).","Check for collisions after git merges and branch switches.","Use go list -f '{{.AllFiles}}' . to enumerate all input files."],"tags":["go","go-build","filesystem","case-sensitivity","cross-platform","validation"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}