{"record":{"id":"448d0e63fc656c3f","repo":"openzipkin/zipkin","slug":"cannot-gunzip-spans","errorCode":null,"errorMessage":"Cannot gunzip spans","messagePattern":"Cannot gunzip spans","errorType":"http","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"zipkin-server/src/main/java/zipkin2/server/internal/ZipkinHttpCollector.java","lineNumber":238,"sourceCode":"\n  @Override public void onError(Throwable t) {\n    completeExceptionally(t);\n  }\n}\n\nfinal class UnzippingBytesRequestConverter {\n\n  static HttpData convertRequest(ServiceRequestContext ctx, AggregatedHttpRequest request) {\n    ZipkinHttpCollector.metrics.incrementMessages();\n    String encoding = request.headers().get(HttpHeaderNames.CONTENT_ENCODING);\n    HttpData content = request.content();\n    if (!content.isEmpty() && encoding != null && encoding.contains(\"gzip\")) {\n      content = StreamDecoderFactory.gzip().newDecoder(ctx.alloc()).decode(content);\n      // The implementation of the armeria decoder is to return an empty body on failure\n      if (content.isEmpty()) {\n        ZipkinHttpCollector.maybeLog(\"Malformed gzip body\", ctx, request);\n        content.close();\n        throw new IllegalArgumentException(\"Cannot gunzip spans\");\n      }\n    }\n\n    if (content.isEmpty()) ZipkinHttpCollector.maybeLog(\"Empty POST body\", ctx, request);\n    if (content.length() == 2 && \"[]\".equals(content.toStringAscii())) {\n      ZipkinHttpCollector.maybeLog(\"Empty JSON list POST body\", ctx, request);\n      content.close();\n      content = HttpData.empty();\n    }\n\n    ZipkinHttpCollector.metrics.incrementBytes(content.length());\n    return content;\n  }\n}\n","sourceCodeStart":220,"sourceCodeEnd":253,"githubUrl":"https://github.com/openzipkin/zipkin/blob/878ce2a1fad54ca941d17fdcf2e1d924b148eb1f/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinHttpCollector.java#L220-L253","documentation":"UnzippingBytesRequestConverter.convertRequest throws IllegalArgumentException ('Cannot gunzip spans') when a POST to the Zipkin HTTP collector declares a gzip Content-Encoding but Armeria's gzip decoder produced an empty body, which the decoder does on failure. This indicates the client sent malformed or truncated gzip data; the request is rejected instead of being treated as an empty span list.","triggerScenarios":"POST /api/v2/spans with Content-Encoding: gzip where the body is not valid gzip (e.g. already-decoded JSON double-gzipped pipeline, cut-off payload from a proxy, or raw bytes with the header added manually).","commonSituations":"A proxy or SDK applies the gzip header without actually compressing; senders re-compress already-compressed bodies; load balancers truncate large compressed batches; curl with --header 'Content-Encoding: gzip' but uncompressed data.","solutions":["Fix the sender to send actual gzip-compressed bytes when the header is present","Remove proxies/interceptors that add or strip Content-Encoding incorrectly","Test with curl --data-binary @spans.gz --header 'Content-Encoding: gzip' --header 'Content-Type: application/json' to confirm valid gzip"],"exampleFix":"# before\ncurl -X POST http://zipkin:9411/api/v2/spans \\\n  -H 'Content-Encoding: gzip' \\\n  --data-binary @spans.json   # plain JSON with gzip header -> error\n\n# after\ngzip -c spans.json > spans.gz\ncurl -X POST http://zipkin:9411/api/v2/spans \\\n  -H 'Content-Encoding: gzip' -H 'Content-Type: application/json' \\\n  --data-binary @spans.gz","handlingStrategy":"validation","validationCode":"// sender side: only set the header when the body is actually gzipped\nbyte[] body = json.getBytes(UTF_8);\nboolean gzipped = false; // set true only when you gzip yourself\nrequest.header(\"Content-Encoding\", gzipped ? \"gzip\" : \"identity\").body(body);","typeGuard":null,"tryCatchPattern":"catch (IllegalArgumentException e) if 'Cannot gunzip spans' -> log the offending payload size/encoding headers, fix the sender's compression logic, and drop the batch (do not retry the same bytes)","preventionTips":["Never let proxies add Content-Encoding: gzip unless they compress the body","Use senders/SDKs that manage gzip themselves instead of manual headers"],"tags":["zipkin","collector","gzip","http","payload"],"backgroundTag":null,"analyzedSha":"878ce2a1fad54ca941d17fdcf2e1d924b148eb1f","analyzedAt":"2026-08-14T15:17:09.895Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}