{"record":{"id":"f272fe2aac99571a","repo":"openzipkin/zipkin","slug":"could-not-detect-the-span-format","errorCode":null,"errorMessage":"Could not detect the span format","messagePattern":"Could not detect the span format","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"zipkin/src/main/java/zipkin2/SpanBytesDecoderDetector.java","lineNumber":90,"sourceCode":"  public static BytesDecoder<Span> decoderForListMessage(ByteBuffer spans) {\n    BytesDecoder<Span> decoder = detectDecoder(spans);\n    byte first = spans.get(spans.position());\n    if (first != 12 /* List[ThriftSpan] */\n        && first != 11 /* openzipkin/zipkin-reporter-java#133 */\n        && !protobuf3(spans) && first != '[') {\n      throw new IllegalArgumentException(\"Expected json, proto3 or thrift list encoding\");\n    }\n    return decoder;\n  }\n\n  /** @throws IllegalArgumentException if the input isn't a json or thrift list or object. */\n  static BytesDecoder<Span> detectDecoder(ByteBuffer bytes) {\n    byte first = bytes.get(bytes.position());\n    if (first <= 16) { // binary format\n      if (protobuf3(bytes)) return SpanBytesDecoder.PROTO3;\n      return SpanBytesDecoder.THRIFT; /* the first byte is the TType, in a range 0-16 */\n    } else if (first != '[' && first != '{') {\n      throw new IllegalArgumentException(\"Could not detect the span format\");\n    }\n    if (contains(bytes, ENDPOINT_FIELD_SUFFIX)) return SpanBytesDecoder.JSON_V2;\n    if (contains(bytes, TAGS_FIELD)) return SpanBytesDecoder.JSON_V2;\n    return SpanBytesDecoder.JSON_V1;\n  }\n\n  static boolean contains(ByteBuffer bytes, byte[] subsequence) {\n    bytes:\n    for (int i = 0; i < bytes.remaining() - subsequence.length + 1; i++) {\n      for (int j = 0; j < subsequence.length; j++) {\n        if (bytes.get(bytes.position() + i + j) != subsequence[j]) {\n          continue bytes;\n        }\n      }\n      return true;\n    }\n    return false;\n  }","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/openzipkin/zipkin/blob/878ce2a1fad54ca941d17fdcf2e1d924b148eb1f/zipkin/src/main/java/zipkin2/SpanBytesDecoderDetector.java#L72-L108","documentation":"SpanBytesDecoderDetector.detectDecoder(ByteBuffer) sniffs the format from the first byte: values <= 16 mean binary (PROTO3 if the protobuf3 heuristic matches, else Thrift); '[' or '{' mean JSON (v2 if it contains \"endpoints\"/\"tags\" fields, else JSON_V1). Anything else throws IllegalArgumentException('Could not detect the span format'). This underlying exception propagates through both decoderForMessage and decoderForListMessage.","triggerScenarios":"Passing payloads whose first byte is > 16 and not '[' or '{' — e.g. undecompressed gzip (0x1f), protobuf field tags > 16, protobuf base64 text, XML, or an empty/garbage buffer offset.","commonSituations":"Forgetting to decompress gzip/deflate from reporters before decoding; feeding base64- or text-encoded spans; reusing a ByteBuffer whose position was advanced by prior reads so detection sees the wrong byte; version mismatches between reporter encoder and collector decoder.","solutions":["Decompress according to Content-Encoding before calling the detector.","Reset/duplicate the ByteBuffer (buf.duplicate().position(0)) if it has been read before.","Verify the producer encodes with one of the supported codecs (THRIFT, JSON_V1, JSON_V2, PROTO3 list forms) and match collector/reporter versions."],"exampleFix":"// before\nBytesDecoder<Span> d = SpanBytesDecoderDetector.decoderForListMessage(buf);\n\n// after\nif (\"gzip\".equals(contentEncoding)) body = gunzip(body);\nBytesDecoder<Span> d = SpanBytesDecoderDetector.decoderForListMessage(ByteBuffer.wrap(body));","handlingStrategy":"try-catch","validationCode":"boolean looksLikeSpanPayload(byte[] p) {\n  if (p.length == 0) return false;\n  byte f = p[0];\n  return f <= 16 || f == '[' || f == '{';\n}","typeGuard":null,"tryCatchPattern":"try {\n  decoder = SpanBytesDecoderDetector.decoderForListMessage(buf);\n} catch (IllegalArgumentException e) {\n  log.warn(\"undecodable payload, first byte={}\", buf.get(buf.position()));\n  metrics.incrementMalformed(); // drop, don't crash the consumer\n}","preventionTips":["Handle Content-Encoding before sniffing bytes.","Duplicate/reset ByteBuffers passed to the detector; never reuse a consumed buffer.","Add a malformed-payload metric to collectors to catch encoder mismatches early."],"tags":["zipkin","codec","decode","format-detection"],"backgroundTag":null,"analyzedSha":"878ce2a1fad54ca941d17fdcf2e1d924b148eb1f","analyzedAt":"2026-08-14T15:17:09.895Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}