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

  1. Retry the token request once — transient truncation and proxy interference often clear on the second attempt.
  2. Disable compression on the OAuth client by sending Accept-Encoding: identity so the server returns an uncompressed body.
  3. Bypass or correctly configure the intercepting proxy for the Anth OAuth host (api.anthropic.com / console.anthropic.com).
  4. 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

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


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/bd103ce93e6bcda2. Report an issue: GitHub.