{"record":{"id":"aa4b7c6a41ced2e7","repo":"openzipkin/zipkin","slug":"s-reading-s-from-tbinary","errorCode":null,"errorMessage":"%s reading %s from TBinary","messagePattern":"(.+?) reading (.+?) from TBinary","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"zipkin/src/main/java/zipkin2/internal/ThriftCodec.java","lineNumber":115,"sourceCode":"    return buffer.readInt();\n  }\n\n  static <T> void writeList(WriteBuffer.Writer<T> writer, List<T> value, WriteBuffer buffer) {\n    int length = value.size();\n    writeListBegin(buffer, length);\n    for (int i = 0; i < length; i++) {\n      writer.write(value.get(i), buffer);\n    }\n  }\n\n  static IllegalArgumentException exceptionReading(String type, Exception e) {\n    String cause = e.getMessage() == null ? \"Error\" : e.getMessage();\n    if (e instanceof EOFException) cause = \"EOF\";\n    if (e instanceof IllegalStateException || e instanceof BufferUnderflowException) {\n      cause = \"Malformed\";\n    }\n    String message = String.format(\"%s reading %s from TBinary\", cause, type);\n    throw new IllegalArgumentException(message, e);\n  }\n\n  static void skip(ReadBuffer buffer, byte type) {\n    skip(buffer, type, MAX_SKIP_DEPTH);\n  }\n\n  static void skip(ReadBuffer buffer, byte type, int maxDepth) {\n    if (maxDepth <= 0) throw new IllegalStateException(\"Maximum skip depth exceeded\");\n    switch (type) {\n      case TYPE_BOOL:\n      case TYPE_BYTE:\n        buffer.skip(1);\n        break;\n      case TYPE_I16:\n        buffer.skip(2);\n        break;\n      case TYPE_I32:\n        buffer.skip(4);","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/openzipkin/zipkin/blob/878ce2a1fad54ca941d17fdcf2e1d924b148eb1f/zipkin/src/main/java/zipkin2/internal/ThriftCodec.java#L97-L133","documentation":"Zipkin's legacy thrift codec wraps decode failures as IllegalArgumentException('<cause> reading <type> from TBinary'), normalizing EOFException to 'EOF' and IllegalStateException/BufferUnderflowException to 'Malformed'. It surfaces when Scribe/legacy storage data or thrift-encoded spans cannot be parsed with the zipkin ThriftLayout.","triggerScenarios":"Calling SpanBytesDecoder.THRIFT.decode/decodeList with bytes that are not the fixed zipkin thrift span layout: wrong field types, truncated structs, or bytes from a different thrift schema.","commonSituations":"Migrating old scribe-collected spans; reading legacy Cassandra rows; a finagle version emitting a revised thrift schema; feeding JSON/proto bytes to a thrift decoder.","solutions":["Read getCause() — EOF means truncation, Malformed means structural mismatch; match your fix accordingly.","Confirm the payload came from zipkin's thrift schema (finagle zipkin tracer, zipkin-thrift definitions), not an unrelated thrift service.","For truncated rows, check storage write limits and re-ingest the trace from the source.","During migrations, dispatch on Content-Type/prefix: JSON starts with '{'/'[', proto3 with 0x0a, thrift begins with a struct field header."],"exampleFix":"// before\nSpan span = SpanBytesDecoder.THRIFT.decodeOne(bytes);\n\n// after\nSpan span;\nif (bytes.length > 0 && (bytes[0] == '{' || bytes[0] == '[')) {\n  span = SpanBytesDecoder.JSON_V2.decodeOne(bytes);\n} else {\n  span = SpanBytesDecoder.THRIFT.decodeOne(bytes);\n}","handlingStrategy":"try-catch","validationCode":"// dispatch on payload shape before choosing a decoder\nSpanBytesDecoder pickDecoder(byte[] b) {\n  if (b.length == 0) throw new IllegalArgumentException(\"empty payload\");\n  char c = (char)(b[0] & 0xff);\n  if (c == '{' || c == '[') return SpanBytesDecoder.JSON_V2;\n  if (c == 0x0a || c == 0x0c) return SpanBytesDecoder.PROTO3;\n  return SpanBytesDecoder.THRIFT;\n}","typeGuard":null,"tryCatchPattern":"try { return SpanBytesDecoder.THRIFT.decodeOne(bytes); } catch (IllegalArgumentException e) { LOG.warn(\"legacy thrift unreadable: {}\", e.getMessage()); return null; }","preventionTips":["During legacy migration, carry an encoding label alongside bytes.","Convert old thrift data to V2 JSON/PROTO3 once, then retire the thrift path."],"tags":["zipkin","thrift","decoding","legacy"],"backgroundTag":null,"analyzedSha":"878ce2a1fad54ca941d17fdcf2e1d924b148eb1f","analyzedAt":"2026-08-14T15:17:09.895Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}