golang/go · info

refs changed

Error message

refs changed

What it means

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.

Source

Thrown at src/cmd/go/internal/modfetch/codehost/git.go:241

		if !ok {
			return fmt.Errorf("ref %q deleted", old.Ref)
		}
		if hash != old.Hash {
			return fmt.Errorf("ref %q moved from %s to %s", old.Ref, old.Hash, hash)
		}
	}
	if old.TagSum != "" {
		tags, err := r.Tags(ctx, old.TagPrefix)
		if err != nil {
			return err
		}
		if tags.Origin.TagSum != old.TagSum {
			return fmt.Errorf("tags changed")
		}
	}
	if old.RepoSum != "" {
		if r.repoSum(r.refs) != old.RepoSum {
			return fmt.Errorf("refs changed")
		}
	}
	return nil
}

// loadRefs loads heads and tags references from the remote into the map r.refs.
// The result is cached in memory.
func (r *gitRepo) loadRefs(ctx context.Context) (map[string]string, error) {
	if r.local { // Return results from the cache if local only.
		// In the future, we could consider loading r.refs using local git commands
		// if desired.
		return nil, nil
	}
	r.refsOnce.Do(func() {
		// The git protocol sends all known refs and ls-remote filters them on the client side,
		// so we might as well record both heads and tags in one shot.
		// Most of the time we only care about tags but sometimes we care about heads too.
		release, err := base.AcquireNet()

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Re-fetch the module: 'go mod download module' or 'go get module@<version>'.
  2. Pin to a specific immutable version to avoid sensitivity to ref churn.
  3. If the error is persistent and unwanted, verify GOPROXY settings allow re-fetch.
  4. Clear cache: 'go clean -cache' then retry.

Example fix

# before: stale RepoSum in cache
go build ./...  # 'refs changed'
# after
go mod download example.com/mod
go build ./...
Defensive patterns

Strategy: fallback

Validate before calling

null

Type guard

null

Try / catch

// 'refs changed' is benign; re-fetch and continue
err := repo.CheckReuse(ctx, old, subdir)
if err != nil && strings.Contains(err.Error(), "refs changed") {
    info, ferr := repo.Stat(ctx, rev)
    if ferr == nil { return useInfo(info) }
    return ferr
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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