{"record":{"id":"880869e7a26b6adc","repo":"golang/go","slug":"origin-moved-from-v-q-to-v-q","errorCode":null,"errorMessage":"origin moved from %v %q to %v %q","messagePattern":"origin moved from (.+?) %q to (.+?) %q","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/modfetch/codehost/vcs.go","lineNumber":385,"sourceCode":"\n// repoSumOrigin returns an Origin containing a RepoSum.\nfunc (r *vcsRepo) repoSumOrigin(ctx context.Context) *Origin {\n\torigin := &Origin{\n\t\tVCS:     r.cmd.vcs,\n\t\tURL:     r.remote,\n\t\tRepoSum: r.repoSum,\n\t}\n\tr.repoSumOnce.Do(func() { r.loadRepoSum(ctx) })\n\torigin.RepoSum = r.repoSum\n\treturn origin\n}\n\nfunc (r *vcsRepo) CheckReuse(ctx context.Context, old *Origin, subdir string) error {\n\tif old == nil {\n\t\treturn fmt.Errorf(\"missing origin\")\n\t}\n\tif old.VCS != r.cmd.vcs || old.URL != r.remote {\n\t\treturn fmt.Errorf(\"origin moved from %v %q to %v %q\", old.VCS, old.URL, r.cmd.vcs, r.remote)\n\t}\n\tif old.Subdir != subdir {\n\t\treturn fmt.Errorf(\"origin moved from %v %q %q to %v %q %q\", old.VCS, old.URL, old.Subdir, r.cmd.vcs, r.remote, subdir)\n\t}\n\n\tif old.Ref == \"\" && old.RepoSum == \"\" && old.Hash != \"\" {\n\t\t// Hash has to remain in repo.\n\t\thash, err := r.lookupRef(ctx, old.Hash)\n\t\tif err == nil && hash == old.Hash {\n\t\t\treturn nil\n\t\t}\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"looking up hash: %v\", err)\n\t\t}\n\t\treturn fmt.Errorf(\"hash changed\") // weird but maybe they made a tag\n\t}\n\n\tif old.Ref != \"\" && old.RepoSum == \"\" {","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/modfetch/codehost/vcs.go#L367-L403","documentation":"CheckReuse compares the old origin's VCS type and URL against the current repo. If either differs, the origin is considered to have moved and reuse is refused. The %v/%q pair shows old vs new VCS and URL.","triggerScenarios":"A cached Origin records VCS=hg URL=A, but the current repo is VCS=hg URL=B (or the VCS type itself changed). Typical when a vanity server redirected the import path to a different backing repo.","commonSituations":"Upstream project migrated hosts (e.g. Bitbucket to GitHub) and updated the go-import meta tag; a vanity server rotated its canonical URL; a replace directive points to a different remote than the cached origin.","solutions":["Run `go clean -modcache` (or remove the specific module directory) so the stale origin is discarded and re-fetched from the new remote.","Align the replace directive with the new upstream URL.","Update the vanity server's go-import meta tag consistently so all clients see the same VCS+URL."],"exampleFix":"// before — cache says hg https://old.example.org/m, meta tag now points to https://new.example.org/m\n$ go build\n// error: origin moved from hg \"https://old.example.org/m\" to hg \"https://new.example.org/m\"\n\n// after\n$ go clean -modcache && go build","handlingStrategy":"fallback","validationCode":"func originMatches(old *codehost.Origin, vcs, url string) bool {\n    return old != nil && old.VCS == vcs && old.URL == url\n}","typeGuard":null,"tryCatchPattern":"if err := repo.CheckReuse(ctx, old, subdir); err != nil {\n    if strings.HasPrefix(err.Error(), \"origin moved\") {\n        // upstream moved — invalidate cache and re-download\n        go cleanModCache(modulePath)\n    }\n}","preventionTips":["When migrating upstream hosts, increment a vanity path version or announce the move so caches can be flushed.","Keep replace directives aligned with the live upstream URL."],"tags":["vcs","checkreuse","origin","vanity-import"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}