{"record":{"id":"f19e76741733d5e2","repo":"openzipkin/zipkin","slug":"truncated-length-bytes-available","errorCode":null,"errorMessage":"Truncated: length {} > bytes available {}","messagePattern":"Truncated: length (.+?) > bytes available (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"zipkin/src/main/java/zipkin2/internal/ReadBuffer.java","lineNumber":375,"sourceCode":"    byte b; // negative number implies MSB set\n    if ((b = readByte()) >= 0) {\n      return b;\n    }\n\n    long result = b & 0x7f;\n    for (int i = 1; b < 0 && i < 10; i++) {\n      b = readByte();\n      if (i == 9 && (b & 0xf0) != 0) {\n        throw new IllegalArgumentException(\"Greater than 64-bit varint at position \" + (pos() - 1));\n      }\n      result |= (long) (b & 0x7f) << (i * 7);\n    }\n    return result;\n  }\n\n  final void require(int byteCount) {\n    if (this.available() < byteCount) {\n      throw new IllegalArgumentException(\n        \"Truncated: length \" + byteCount + \" > bytes available \" + this.available());\n    }\n  }\n\n  int checkReadArguments(byte[] dst, int offset, int length) {\n    if (dst == null) throw new NullPointerException();\n    if (offset < 0 || length < 0 || length > dst.length - offset) {\n      throw new IndexOutOfBoundsException();\n    }\n    return Math.min(available(), length);\n  }\n}\n","sourceCodeStart":357,"sourceCodeEnd":388,"githubUrl":"https://github.com/openzipkin/zipkin/blob/878ce2a1fad54ca941d17fdcf2e1d924b148eb1f/zipkin/src/main/java/zipkin2/internal/ReadBuffer.java#L357-L388","documentation":"ReadBuffer.require(byteCount) is called before every fixed-size read (IDs, timestamps, fixed32/64 fields); when fewer bytes remain than the field needs it throws 'Truncated: length N > bytes available M'. It means the payload ended in the middle of a span — a length prefix promised more data than the transport delivered.","triggerScenarios":"Decoding a proto3/thrift span whose declared field length (or the outer list length) exceeds the actual byte count: cut-off HTTP bodies, partial Kafka messages, rows truncated by a storage max-size setting, or a producer bug writing lengths larger than the data.","commonSituations":"Server/collector request-size limits silently truncating bodies; network interruptions on large span batches; a database column too small for the blob so only a prefix was stored.","solutions":["Compare the payload's declared lengths against its actual size at the producer; log both.","Raise or fix transport limits (spring.servlet.multipart.max-request-size, Kafka max.message.bytes, DB column type BLOB vs MEDIUMBLOB) so truncation cannot happen.","Verify checksums/length framing end-to-end (Content-Length, TLS, producer acks) for large batches.","Re-send the batch from the source; truncated data is unrecoverable and must be dropped."],"exampleFix":"# before (zipkin-server)\n# default multipart limits truncated large JSON/proto uploads\n\n# after\nserver.tomcat.max-http-form-post-size=-1\nspring.servlet.multipart.max-file-size=100MB\nspring.servlet.multipart.max-request-size=100MB","handlingStrategy":"validation","validationCode":"// before decode, if the format carries a declared length, compare it\nboolean isComplete(byte[] payload, int declaredLen) { return payload.length >= declaredLen; }","typeGuard":null,"tryCatchPattern":"catch (IllegalArgumentException e) { if (e.getMessage().startsWith(\"Truncated\")) { LOG.error(\"truncated span batch: {}\", e.getMessage()); requestResend(); } }","preventionTips":["Size transport limits above your max span batch (HTTP body caps, Kafka max.message.bytes, DB BLOB size).","Use Content-Length and verify byte counts on both ends.","Do not retry truncated payloads — re-ingest from the source."],"tags":["zipkin","truncated","transport","decoding"],"backgroundTag":null,"analyzedSha":"878ce2a1fad54ca941d17fdcf2e1d924b148eb1f","analyzedAt":"2026-08-14T15:17:09.895Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}