golang/go · error

origin moved from %v %q %q to %v %q %q

Error message

origin moved from %v %q %q to %v %q %q

What it means

CheckReuse's second move-detection: the VCS and URL match but the subdir component differs. The %v/%q tuple shows old (VCS, URL, Subdir) vs new (VCS, URL, subdir argument). Means the module is being resolved from a different subdirectory of the same repo than before.

Source

Thrown at src/cmd/go/internal/modfetch/codehost/vcs.go:388

	origin := &Origin{
		VCS:     r.cmd.vcs,
		URL:     r.remote,
		RepoSum: r.repoSum,
	}
	r.repoSumOnce.Do(func() { r.loadRepoSum(ctx) })
	origin.RepoSum = r.repoSum
	return origin
}

func (r *vcsRepo) CheckReuse(ctx context.Context, old *Origin, subdir string) error {
	if old == nil {
		return fmt.Errorf("missing origin")
	}
	if old.VCS != r.cmd.vcs || old.URL != r.remote {
		return fmt.Errorf("origin moved from %v %q to %v %q", old.VCS, old.URL, r.cmd.vcs, r.remote)
	}
	if old.Subdir != subdir {
		return fmt.Errorf("origin moved from %v %q %q to %v %q %q", old.VCS, old.URL, old.Subdir, r.cmd.vcs, r.remote, subdir)
	}

	if old.Ref == "" && old.RepoSum == "" && old.Hash != "" {
		// Hash has to remain in repo.
		hash, err := r.lookupRef(ctx, old.Hash)
		if err == nil && hash == old.Hash {
			return nil
		}
		if err != nil {
			return fmt.Errorf("looking up hash: %v", err)
		}
		return fmt.Errorf("hash changed") // weird but maybe they made a tag
	}

	if old.Ref != "" && old.RepoSum == "" {
		hash, err := r.lookupRef(ctx, old.Ref)
		if err == nil && hash != "" && hash == old.Hash {
			return nil

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Clear the module cache entry: `go clean -modcache` or delete GOMODCACHE/cache/download/<module>/ and re-download.
  2. Verify the go-import meta tag's subdir is stable and matches the module's actual location in the repo.
  3. Confirm the import path in go.mod matches the path the meta tag advertises.
Defensive patterns

Strategy: fallback

Validate before calling

func subdirMatches(old *codehost.Origin, subdir string) bool {
    return old != nil && old.Subdir == subdir
}

Try / catch

if err := repo.CheckReuse(ctx, old, subdir); err != nil {
    if strings.Contains(err.Error(), "origin moved") && strings.Contains(err.Error(), old.Subdir) {
        // subdir changed — invalidate and re-resolve
    }
}

Prevention

When it happens

Trigger: Same repo URL but the caller passed a different subdir to CheckReuse than what is recorded in old.Subdir. Happens when a go-import meta tag's subdir attribute changed (new in Go 1.25) or the codeRoot computation shifted.

Common situations: A monorepo moved the module into a different subdirectory and updated its meta tag; the cached origin's Subdir is stale after a repo reorganisation; a hand-edited go.mod with a mismatched path.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/8279d5e6aac1a116. Report an issue: GitHub.