{"record":{"id":"fc714b6808d0f919","repo":"golang/go","slug":"parsing-s-v","errorCode":null,"errorMessage":"parsing %s: %v","messagePattern":"parsing (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/modload/list.go","lineNumber":59,"sourceCode":"// along with any error preventing additional matches from being identified.\n//\n// The returned slice can be nonempty even if the error is non-nil.\nfunc ListModules(ld *Loader, ctx context.Context, args []string, mode ListMode, reuseFile string) ([]*modinfo.ModulePublic, error) {\n\tvar reuse map[module.Version]*modinfo.ModulePublic\n\tif reuseFile != \"\" {\n\t\tdata, err := os.ReadFile(reuseFile)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdec := json.NewDecoder(bytes.NewReader(data))\n\t\treuse = make(map[module.Version]*modinfo.ModulePublic)\n\t\tfor {\n\t\t\tvar m modinfo.ModulePublic\n\t\t\tif err := dec.Decode(&m); err != nil {\n\t\t\t\tif err == io.EOF {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\treturn nil, fmt.Errorf(\"parsing %s: %v\", reuseFile, err)\n\t\t\t}\n\t\t\tif m.Origin == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tm.Reuse = true\n\t\t\treuse[module.Version{Path: m.Path, Version: m.Version}] = &m\n\t\t\tif m.Query != \"\" {\n\t\t\t\treuse[module.Version{Path: m.Path, Version: m.Query}] = &m\n\t\t\t}\n\t\t}\n\t}\n\n\trs, mods, err := listModules(ld, ctx, LoadModFile(ld, ctx), args, mode, reuse)\n\n\ttype token struct{}\n\tsem := make(chan token, runtime.GOMAXPROCS(0))\n\tif mode != 0 {\n\t\tfor _, m := range mods {","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/modload/list.go#L41-L77","documentation":"Thrown by ListModules (list.go:59) when parsing the reuse file — a JSON stream of modinfo.ModulePublic records used to cache prior 'go list -m' output for incremental reuse. A json.NewDecoder reads the file record-by-record; any decode error that is not io.EOF is wrapped with the reuse file path. The reuse file is passed by the caller as the reuseFile parameter.","triggerScenarios":"The 'go list -m' command (or callers like IDE tooling) is invoked with a reuseFile path that contains malformed, truncated, or non-JSON content. A partial write or crash during a previous run left a corrupt reuse cache file.","commonSituations":"The Go command's internal cache or a tool's reuse file was corrupted by an interrupted process. Disk issues or manual edits to cache files. Concurrent processes writing to the same reuse file.","solutions":["Delete or regenerate the reuse cache file — the Go command will rebuild it from scratch.","Run 'go clean -cache' to clear all cached data if the file path is not obvious.","If calling ListModules programmatically, pass an empty reuseFile string to skip reuse, or ensure the reuseFile is written atomically."],"exampleFix":"// before — reusing a corrupt cache file\ngo list -m -reuse=/tmp/stale_cache.json all\n\n// after — drop the reuse flag or delete the file\nrm -f /tmp/stale_cache.json\ngo list -m all","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// When calling ListModules with a reuseFile, handle parse errors gracefully.\nmods, err := modload.ListModules(ld, ctx, args, mode, reuseFile)\nif err != nil {\n    // If the error is a reuse-file parse error, retry without reuse.\n    if strings.Contains(err.Error(), \"parsing \") {\n        os.Remove(reuseFile)\n        mods, err = modload.ListModules(ld, ctx, args, mode, \"\")\n    }\n}","preventionTips":["Write reuse/cache files atomically (write to temp, then rename) to avoid corruption from interrupted writes.","Avoid concurrent processes writing to the same reuse file.","Periodically clean caches with 'go clean -cache' if corruption is suspected."],"tags":["go-list","json","cache","reuse","corruption"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:17:08.281Z"}