{"record":{"id":"ab0a187e22d03c19","repo":"golang/go","slug":"refs-changed","errorCode":null,"errorMessage":"refs changed","messagePattern":"refs changed","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"info","filePath":"src/cmd/go/internal/modfetch/codehost/git.go","lineNumber":241,"sourceCode":"\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"ref %q deleted\", old.Ref)\n\t\t}\n\t\tif hash != old.Hash {\n\t\t\treturn fmt.Errorf(\"ref %q moved from %s to %s\", old.Ref, old.Hash, hash)\n\t\t}\n\t}\n\tif old.TagSum != \"\" {\n\t\ttags, err := r.Tags(ctx, old.TagPrefix)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif tags.Origin.TagSum != old.TagSum {\n\t\t\treturn fmt.Errorf(\"tags changed\")\n\t\t}\n\t}\n\tif old.RepoSum != \"\" {\n\t\tif r.repoSum(r.refs) != old.RepoSum {\n\t\t\treturn fmt.Errorf(\"refs changed\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// loadRefs loads heads and tags references from the remote into the map r.refs.\n// The result is cached in memory.\nfunc (r *gitRepo) loadRefs(ctx context.Context) (map[string]string, error) {\n\tif r.local { // Return results from the cache if local only.\n\t\t// In the future, we could consider loading r.refs using local git commands\n\t\t// if desired.\n\t\treturn nil, nil\n\t}\n\tr.refsOnce.Do(func() {\n\t\t// The git protocol sends all known refs and ls-remote filters them on the client side,\n\t\t// so we might as well record both heads and tags in one shot.\n\t\t// Most of the time we only care about tags but sometimes we care about heads too.\n\t\trelease, err := base.AcquireNet()","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/modfetch/codehost/git.go#L223-L259","documentation":"Thrown by gitRepo.CheckReuse when old.RepoSum is set and the current repo-wide ref checksum (computed over all refs via repoSum) differs from the recorded value. This is a coarser check than TagSum — it covers the entire ref set, so any ref change (heads or tags) triggers it.","triggerScenarios":"CheckReuse where any ref in the upstream repo changed since the cache entry was written: new commits on any branch, new tags, deleted branches. RepoSum hashes the full refs map from ls-remote.","commonSituations":"Upstream repo received new commits or tags since last cache; depending on a module via a branch or HEAD; the module is under active development. Like 'tags changed' but broader scope.","solutions":["Re-fetch the module: 'go mod download module' or 'go get module@<version>'.","Pin to a specific immutable version to avoid sensitivity to ref churn.","If the error is persistent and unwanted, verify GOPROXY settings allow re-fetch.","Clear cache: 'go clean -cache' then retry."],"exampleFix":"# before: stale RepoSum in cache\ngo build ./...  # 'refs changed'\n# after\ngo mod download example.com/mod\ngo build ./...","handlingStrategy":"fallback","validationCode":"null","typeGuard":"null","tryCatchPattern":"// 'refs changed' is benign; re-fetch and continue\nerr := repo.CheckReuse(ctx, old, subdir)\nif err != nil && strings.Contains(err.Error(), \"refs changed\") {\n    info, ferr := repo.Stat(ctx, rev)\n    if ferr == nil { return useInfo(info) }\n    return ferr\n}","preventionTips":["Pin modules to immutable versions to reduce ref-check sensitivity.","Periodically refresh the cache with 'go mod download'.","If these errors are noisy, pin to commit hashes for full determinism."],"tags":["git","cache-reuse","refs","upstream-change","benign"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}