router-for-me/CLIProxyAPI · error
decode Claude OAuth gzip response: %w
Error message
decode Claude OAuth gzip response: %w
What it means
decodeClaudeOAuthEncoding decodes the Claude OAuth token-endpoint response according to its Content-Encoding header. This variant fires when the header says gzip but gzip.NewReader cannot parse the body, meaning the bytes are not a valid gzip stream. Typical causes are a truncated body, a plain-text body mislabeled as gzip, or an intermediary (proxy) mangling the response.
Source
Thrown at internal/auth/claude/oauth_response.go:46
if encoding == "" || encoding == "identity" {
continue
}
var errDecode error
encoded, errDecode = decodeClaudeOAuthEncoding(encoded, encoding)
if errDecode != nil {
return nil, errDecode
}
}
return encoded, nil
}
func decodeClaudeOAuthEncoding(encoded []byte, encoding string) ([]byte, error) {
var reader io.ReadCloser
switch encoding {
case "gzip":
gzipReader, errGzip := gzip.NewReader(bytes.NewReader(encoded))
if errGzip != nil {
return nil, fmt.Errorf("decode Claude OAuth gzip response: %w", errGzip)
}
reader = gzipReader
case "deflate":
zlibReader, errZlib := zlib.NewReader(bytes.NewReader(encoded))
if errZlib == nil {
reader = zlibReader
} else {
reader = flate.NewReader(bytes.NewReader(encoded))
}
case "br":
reader = io.NopCloser(brotli.NewReader(bytes.NewReader(encoded)))
case "compress":
reader = lzw.NewReader(bytes.NewReader(encoded), lzw.MSB, 8)
default:
return nil, fmt.Errorf("decode Claude OAuth response: unsupported content encoding %q", encoding)
}
decoded, errDecoded := io.ReadAll(reader)
if errDecoded != nil {View on GitHub (pinned to 78f0c4079e)
Solutions
- Retry the token request once — transient truncation and proxy interference often clear on the second attempt.
- Disable compression on the OAuth client by sending Accept-Encoding: identity so the server returns an uncompressed body.
- Bypass or correctly configure the intercepting proxy for the Anth OAuth host (api.anthropic.com / console.anthropic.com).
- Capture the raw response bytes and verify with `curl --compressed` whether the server or the proxy is producing the bad gzip stream.
Example fix
// before
req.Header.Set("Accept-Encoding", "gzip")
// after
req.Header.Set("Accept-Encoding", "identity") // let the server skip compression Defensive patterns
Strategy: retry
Validate before calling
req.Header.Set("Accept-Encoding", "identity") // sidestep gzip entirely Try / catch
var decodeErr error
for attempt := 0; attempt < 2; attempt++ {
body, decodeErr = claude.DecodeOAuthResponse(resp)
if decodeErr == nil { break }
if !strings.Contains(decodeErr.Error(), "gzip") { break }
time.Sleep(time.Second)
} Prevention
- Request identity encoding for OAuth token endpoints to avoid decompression entirely.
- Exclude OAuth hosts from TLS-inspecting proxies.
When it happens
Trigger: POST to the Claude OAuth token/refresh endpoint returns Content-Encoding: gzip with a body that is corrupt, truncated (connection cut mid-read), or actually uncompressed; a corporate proxy or captive portal rewrites the response and breaks the gzip framing.
Common situations: Intercepting proxies (mitmproxy, Zscaler, corporate TLS inspection) that decode and re-encode bodies incorrectly; flaky networks truncating responses; servers that send identity bodies with a stale gzip header under load; local replay/snapshot test fixtures recorded without the gzip bytes.
Related errors
- decode Claude OAuth %s response: %w
- close Claude OAuth %s decoder: %w
- fetch Claude OAuth %s: %w
- read Claude OAuth %s response: %w
- decode Claude OAuth response: unsupported content encoding %
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/bd103ce93e6bcda2.
Report an issue: GitHub.