{"record":{"id":"306746c77c1ec2cb","repo":"golang/go","slug":"internal-error-invalid-binary-cache-entry-not-a","errorCode":null,"errorMessage":"internal error: invalid binary cache entry: not a directory","messagePattern":"internal error: invalid binary cache entry: not a directory","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/cache/cache.go","lineNumber":618,"sourceCode":"\tinfo, err := os.Stat(name)\n\tif executableName != \"\" {\n\t\t// This is an executable file. The file at name won't hold the output itself, but will\n\t\t// be a directory that holds the output, named according to executableName. Check to see\n\t\t// if the directory already exists, and if it does not, create it. Then reset name\n\t\t// to the name we want the output written to.\n\t\tif err != nil {\n\t\t\tif !os.IsNotExist(err) {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := os.Mkdir(name, 0o777); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif info, err = os.Stat(name); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif !info.IsDir() {\n\t\t\treturn errors.New(\"internal error: invalid binary cache entry: not a directory\")\n\t\t}\n\n\t\t// directory exists. now set name to the inner file\n\t\tname = filepath.Join(name, executableName)\n\t\tinfo, err = os.Stat(name)\n\t}\n\tif err == nil && info.Size() == size {\n\t\t// Check hash.\n\t\tif f, err := os.Open(name); err == nil {\n\t\t\th := sha256.New()\n\t\t\tio.Copy(h, f)\n\t\t\tf.Close()\n\t\t\tvar out2 OutputID\n\t\t\th.Sum(out2[:0])\n\t\t\tif out == out2 {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}","sourceCodeStart":600,"sourceCodeEnd":636,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/cache/cache.go#L600-L636","documentation":"When caching executable outputs, the cache uses a directory structure: the output path is a directory containing the named executable file. If os.Stat shows the path exists but is NOT a directory, the cache is in an inconsistent state — a regular file exists where the code expects a directory to hold the executable. This is flagged as an internal error because it represents a format-level violation.","triggerScenarios":"The executable caching path in the put() function (cache.go:617) finds that 'name' exists (os.Stat succeeds), but info.IsDir() returns false. The code path is entered when executableName != '' and an existing entry was found at the expected path.","commonSituations":"Cache format migration issue between Go versions that changed how executables are stored (old version wrote a plain file, new version expects a directory); manual tampering with cache files; partial restore from backup mixing formats; a previous crash left the cache in an inconsistent state.","solutions":["Run go clean -cache to remove all entries and rebuild with the current format","Ensure you are using a consistent Go toolchain version across builds","Remove the specific corrupt cache directory entry if the path is known","If migrating Go versions, always clean the cache after upgrading"],"exampleFix":"// before: stale cache from previous Go version expects directory but finds file\n// $ go build ./... # fails with 'internal error: invalid binary cache entry: not a directory'\n\n// after: clean cache after Go version upgrade\n// $ go clean -cache && go build ./...","handlingStrategy":"validation","validationCode":"// Before builds, verify the cache isn't in a mixed-format state.\n// Simplest check: if Go version changed, always clean.\nfunc ensureCacheFormatConsistent(goVersion string) {\n    marker := filepath.Join(os.Getenv(\"GOCACHE\"), \".go-version\")\n    cached, err := os.ReadFile(marker)\n    if err == nil && string(cached) == goVersion {\n        return // same version, cache is likely fine\n    }\n    fmt.Println(\"Go version changed or unknown — cleaning cache\")\n    exec.Command(\"go\", \"clean\", \"-cache\").Run()\n    os.WriteFile(marker, []byte(goVersion), 0644)\n}","typeGuard":"func isInvalidBinaryEntry(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"invalid binary cache entry\")\n}","tryCatchPattern":"// This is a write-path error (put), not a read-path error.\n// It occurs when the cache tries to store an executable.\n// The error is returned directly, not wrapped in entryNotFoundError.\n//\n// if err := cache.Put(...); err != nil {\n//     if isInvalidBinaryEntry(err) {\n//         // Clean cache and retry\n//         exec.Command(\"go\", \"clean\", \"-cache\").Run()\n//         cache.Put(...) // retry\n//     }\n// }","preventionTips":["Always run go clean -cache after upgrading Go versions","Never partially restore a cache directory from backup","Ensure consistent Go toolchain versions across builds sharing a cache","Don't manually modify or mix cache directory contents"],"tags":["go","build-cache","corruption","disk-cache","executable","internal-error"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}