golang/go · error · module.VersionError

proxy returned info for version %s instead of requested vers

Error message

proxy returned info for version %s instead of requested version

What it means

proxyRepo.Stat verifies the .info response: if the requested version was already canonical and module.Check accepted it for the path, the proxy MUST echo that exact version. Returning a different version (e.g. mapping v1.2.3 to v1.2.4) is a protocol violation and is rejected.

Source

Thrown at src/cmd/go/internal/modfetch/proxy.go:386

func (p *proxyRepo) Stat(ctx context.Context, rev string) (*RevInfo, error) {
	encRev, err := module.EscapeVersion(rev)
	if err != nil {
		return nil, p.versionError(rev, err)
	}
	data, err := p.getBytes(ctx, "@v/"+encRev+".info")
	if err != nil {
		return nil, p.versionError(rev, err)
	}
	info := new(RevInfo)
	if err := json.Unmarshal(data, info); err != nil {
		return nil, p.versionError(rev, fmt.Errorf("invalid response from proxy %q: %w", p.redactedBase, err))
	}
	if info.Version != rev && rev == module.CanonicalVersion(rev) && module.Check(p.path, rev) == nil {
		// If we request a correct, appropriate version for the module path, the
		// proxy must return either exactly that version or an error — not some
		// arbitrary other version.
		return nil, p.versionError(rev, fmt.Errorf("proxy returned info for version %s instead of requested version", info.Version))
	}
	return info, nil
}

func (p *proxyRepo) Latest(ctx context.Context) (*RevInfo, error) {
	data, err := p.getBytes(ctx, "@latest")
	if err != nil {
		if !errors.Is(err, fs.ErrNotExist) {
			return nil, p.versionError("", err)
		}
		return p.latest(ctx)
	}
	info := new(RevInfo)
	if err := json.Unmarshal(data, info); err != nil {
		return nil, p.versionError("", fmt.Errorf("invalid response from proxy %q: %w", p.redactedBase, err))
	}
	return info, nil
}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Switch to a standards-compliant proxy (https://proxy.golang.org,direct).
  2. Pin the exact version you want and report the bug to the proxy operator.
  3. If self-hosting, ensure Stat returns Version == requested canonical version (or a 404/410).
Defensive patterns

Strategy: validation

Validate before calling

// Before trusting Stat output, ensure the proxy echoes the requested version.
// (mirrors the go command's own invariant)
func statEchoes(repo Repo, ctx context.Context, rev string) error {
    info, err := repo.Stat(ctx, rev)
    if err != nil { return err }
    if info.Version != rev { return fmt.Errorf("proxy echoed %s, want %s", info.Version, rev) }
    return nil
}

Try / catch

if _, err := repo.Stat(ctx, rev); err != nil {
    if strings.Contains(err.Error(), "instead of requested version") {
        // switch GOPROXY entry or fall back to direct
    }
}

Prevention

When it happens

Trigger: info.Version != rev AND rev == module.CanonicalVersion(rev) AND module.Check(path, rev) == nil. The proxy substituted a different version in its response.

Common situations: A proxy that 'resolves' versions upward (e.g. redirects v1.2.3 to latest v1.2.x); a redirecting mirror that rewrites versions; a fork proxy mapping tags inconsistently.

Related errors


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