{"record":{"id":"c7e1af9f61cd86cf","repo":"golang/go","slug":"gocacheprog-didn-t-populate-diskpath-on-get-hit","errorCode":null,"errorMessage":"GOCACHEPROG didn't populate DiskPath on get hit","messagePattern":"GOCACHEPROG didn't populate DiskPath on get hit","errorType":"exception","errorClass":"entryNotFoundError","httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/cache/prog.go","lineNumber":290,"sourceCode":"\t\tCommand:  cacheprog.CmdGet,\n\t\tActionID: a[:],\n\t})\n\tif err != nil {\n\t\treturn Entry{}, err // TODO(bradfitz): or entryNotFoundError? Audit callers.\n\t}\n\tif res.Miss {\n\t\treturn Entry{}, &entryNotFoundError{}\n\t}\n\te := Entry{\n\t\tSize: res.Size,\n\t}\n\tif res.Time != nil {\n\t\te.Time = *res.Time\n\t} else {\n\t\te.Time = time.Now()\n\t}\n\tif res.DiskPath == \"\" {\n\t\treturn Entry{}, &entryNotFoundError{errors.New(\"GOCACHEPROG didn't populate DiskPath on get hit\")}\n\t}\n\tif copy(e.OutputID[:], res.OutputID) != len(res.OutputID) {\n\t\treturn Entry{}, &entryNotFoundError{errors.New(\"incomplete ProgResponse OutputID\")}\n\t}\n\tc.noteOutputFile(e.OutputID, res.DiskPath)\n\treturn e, nil\n}\n\nfunc (c *ProgCache) noteOutputFile(o OutputID, diskPath string) {\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\tc.outputFile[o] = diskPath\n}\n\nfunc (c *ProgCache) OutputFile(o OutputID) string {\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\treturn c.outputFile[o]","sourceCodeStart":272,"sourceCodeEnd":308,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/cache/prog.go#L272-L308","documentation":"The GOCACHEPROG program returned a cache hit response (Miss=false) but left the DiskPath field empty. A hit response must include the on-disk path to the output file so the Go toolchain can read it. An empty DiskPath on a reported hit violates the cacheprog protocol contract — the program claims to have the data but doesn't say where.","triggerScenarios":"ProgCache.Get() receives a cacheprog.Response with res.Miss == false and res.DiskPath == ''. The code checks this condition right after confirming it's not a miss.","commonSituations":"Bug in the GOCACHEPROG program — it reports a hit but forgets to populate DiskPath; the program's storage backend had an issue locating the cached output path; protocol version mismatch between Go and the cache program; the program uses a non-standard storage model that doesn't map to on-disk paths.","solutions":["Report or fix the bug in the GOCACHEPROG program — it must set DiskPath on every hit response","Update the GOCACHEPROG program to a version compatible with your Go release's cacheprog protocol","Check the cacheprog protocol documentation (cmd/internal/cacheprog) the program should implement","Temporarily unset GOCACHEPROG to use the default disk cache while debugging","Review the program's Get handler to ensure it always sets DiskPath when Miss is false"],"exampleFix":"// before: GOCACHEPROG program omits DiskPath on hits\n// (in the cache program's Get handler)\n// func handleGet(req *Request) *Response {\n//     return &Response{Miss: false}  // missing DiskPath!\n// }\n\n// after: always set DiskPath when reporting a hit\n// func handleGet(req *Request) *Response {\n//     path, ok := store.Lookup(req.ActionID)\n//     if !ok {\n//         return &Response{Miss: true}\n//     }\n//     return &Response{Miss: false, DiskPath: path, OutputID: outID, Size: size}\n// }","handlingStrategy":"validation","validationCode":"// Validate that the GOCACHEPROG program correctly implements the protocol\n// by running a test get operation and checking the response fields.\n// This requires implementing a small test harness that speaks the cacheprog\n// JSON protocol over stdin/stdout.\n//\n// At minimum, verify the program's documentation or changelog confirms\n// it sets DiskPath on hit responses for your Go version.","typeGuard":"func isMissingDiskPath(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"didn't populate DiskPath\")\n}","tryCatchPattern":"// entry, err := progCache.Get(id)\n// if err != nil {\n//     if isMissingDiskPath(err) {\n//         // The cache program has a protocol bug.\n//         // Fall back to disk cache.\n//         os.Unsetenv(\"GOCACHEPROG\")\n//         entry, err = diskCache.Get(id)\n//     }\n//     if err != nil {\n//         // Rebuild from source\n//         output = rebuild()\n//     }\n// }","preventionTips":["Test the GOCACHEPROG program with a known cache entry before production use","Review the cache program's source code to verify it always sets DiskPath on hits","Keep a fallback build configuration without GOCACHEPROG","File a bug report with the cache program maintainer if DiskPath is missing on hits","Check protocol compatibility between your Go version and the cache program version"],"tags":["go","build-cache","cacheprog","protocol-violation","ipc"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}