golang/go · error · module.VersionError
invalid response from proxy %q: %w
Error message
invalid response from proxy %q: %w
What it means
proxyRepo.Stat unmarshals the JSON body of `@v/{encRev}.info` into a RevInfo. If the proxy returns non-JSON or malformed JSON, json.Unmarshal fails and the error is wrapped with the proxy's redacted base URL for diagnosis.
Source
Thrown at src/cmd/go/internal/modfetch/proxy.go:380
return nil, p.versionError("", codehost.ErrNoCommits)
}
// Call Stat to get all the other fields, including Origin information.
return p.Stat(ctx, bestVersion)
}
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)
}View on GitHub (pinned to b6b368adc5)
Solutions
- Inspect what the proxy actually returned: curl -i {proxy}/{module}/@v/{ver}.info.
- Bypass the failing proxy: GOPROXY=direct or GONOPROXY for the path.
- If you operate the proxy, ensure .info returns strict JSON: {"Version":"...","Time":"...","Origin":{...}}.
- Add the proxy host to NO_PROXY if it is intercepting all traffic unintentionally.
Defensive patterns
Strategy: try-catch
Validate before calling
// Smoke-test the .info endpoint before relying on Stat in automation.
func probeInfo(proxy, mod, ver string) error {
resp, err := http.Get(proxy + "/" + mod + "/@v/" + ver + ".info")
if err != nil { return err }
defer resp.Body.Close()
var v struct{ Version, Time string }
return json.NewDecoder(resp.Body).Decode(&v)
} Try / catch
_, err := repo.Stat(ctx, rev)
if err != nil {
if strings.Contains(err.Error(), "invalid response from proxy") {
// fall back to direct or another proxy entry
}
} Prevention
- Use a conformant HTTPS proxy such as proxy.golang.org.
- Watch for captive portals / corporate TLS intercept on the proxy host.
When it happens
Trigger: getBytes succeeds (200 OK) but body is HTML error page, partial JSON, wrong content type, or otherwise invalid; json.Unmarshal returns non-nil.
Common situations: Corporate proxy returning an HTML login/captive portal; proxy returning a 200 with an error envelope; misbehaving self-hosted proxy; transient CDN corruption.
Related errors
- proxy returned info for version %s instead of requested vers
- parsing go.mod: missing module line
- ${e.Err}
- decoding go list json: %v
- can't decode input %s: %v
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/56c8fde511308a87.
Report an issue: GitHub.