pinpoint-apm/pinpoint · warning

OTLP/HTTP trace request rejected. Unsupported Content-Encodi

Error message

OTLP/HTTP trace request rejected. Unsupported Content-Encoding={}

What it means

OtlpTraceDecompressionFilter.doFilterInternal rejects OTLP/HTTP trace requests whose Content-Encoding is not 'gzip'. The OTLP/HTTP spec only defines gzip compression; anything else (identity mislabeled, deflate, br, or multi-encodings like 'gzip, br') is rejected up front with HTTP 415 UNSUPPORTED_MEDIA_TYPE so the caller gets an explicit error instead of an opaque 400 from a garbled undecoded protobuf body.

Source

Thrown at otlptrace/otlptrace-collector/src/main/java/com/navercorp/pinpoint/otlp/trace/collector/controller/OtlpTraceDecompressionFilter.java:93

    public OtlpTraceDecompressionFilter(int maxDecompressedBytes, OtlpTraceIngestMetrics ingestMetrics) {
        this.maxDecompressedBytes = maxDecompressedBytes;
        this.ingestMetrics = Objects.requireNonNull(ingestMetrics, "ingestMetrics");
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        final String encoding = request.getHeader(HttpHeaders.CONTENT_ENCODING);
        if (encoding == null || encoding.isBlank() || IDENTITY.equalsIgnoreCase(encoding.trim())) {
            filterChain.doFilter(request, response);
            return;
        }
        if (!GZIP.equalsIgnoreCase(encoding.trim())) {
            // Only gzip is defined for OTLP/HTTP; reject anything else (incl. multi-encoding) explicitly
            // rather than letting an undecoded body fail later as an opaque 400.
            logger.warn("OTLP/HTTP trace request rejected. Unsupported Content-Encoding={}", encoding);
            ingestMetrics.requestRejected(OtlpTraceIngestMetrics.Transport.HTTP, OtlpTraceIngestMetrics.RequestRejectReason.UNSUPPORTED_ENCODING);
            response.setStatus(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
            return;
        }

        filterChain.doFilter(new GzipRequestWrapper(request, maxDecompressedBytes), response);
    }

    /**
     * Presents a gzip-encoded request as its decompressed body. Content-Length now describes the
     * compressed size, so it is cleared (reported as unknown) to stop a downstream reader from
     * truncating the inflated stream at the compressed length.
     */
    private static final class GzipRequestWrapper extends HttpServletRequestWrapper {
        private final int limit;
        // Created lazily and cached so repeated getInputStream() calls return the same instance
        // (servlet wrapper contract). A second GZIPInputStream over the already-consumed underlying
        // stream would otherwise fail to re-read the gzip header. Single-threaded per request.

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Set the OTLP exporter's compression to gzip (OTEL_EXPORTER_OTLP_COMPRESSION=gzip or the SDK's compression option).
  2. Remove any Content-Encoding header injection by intermediate proxies/load balancers.
  3. Send the request uncompressed (no Content-Encoding) if compression is not needed — the filter passes it through.
  4. If using a custom client, do not send multiple encodings; gzip alone is accepted.

Example fix

// before
OtlpHttpTraceExporter.builder()
    .setCompression("deflate")
    .build();

// after
OtlpHttpTraceExporter.builder()
    .setCompression("gzip")
    .build();
Defensive patterns

Strategy: validation

Validate before calling

// client-side, before sending
String enc = request.getHeader("Content-Encoding");
boolean ok = enc == null || "gzip".equalsIgnoreCase(enc.trim());
if (!ok) {
    throw new IllegalStateException("OTLP/HTTP allows only gzip Content-Encoding, got: " + enc);
}

Prevention

When it happens

Trigger: Sending a POST to the OTLP/HTTP trace endpoint with a Content-Encoding header other than 'gzip' (e.g. 'deflate', 'zstd', 'br', 'gzip, deflate', or 'identity' while actually compressing).

Common situations: Client SDK configured with a non-default compression (zstd/deflate), an HTTP proxy or gateway adding its own Content-Encoding on top, or a client compressing with 'identity' set. Often surfaces after upgrading an SDK where compression defaulted to none before.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07). Data as JSON: /api/errors/e85092fd071c3620. Report an issue: GitHub.