openzipkin/zipkin · error · IllegalArgumentException

Malformed: fieldNumber was zero at byte

Error message

Malformed: fieldNumber was zero at byte 

What it means

Protobuf field keys are varints where fieldNumber = key >>> 3; a key whose top 3 bits of the tag (the field number portion) are zero is invalid, because field numbers start at 1. Proto3Fields.Field.fieldNumber throws 'Malformed: fieldNumber was zero at byte N' (with the byte offset) when it decodes such a key while reading a span. This almost always means the byte stream is not the expected protobuf message.

Source

Thrown at zipkin/src/main/java/zipkin2/internal/Proto3Fields.java:52

     *
     * <p>See https://developers.google.com/protocol-buffers/docs/encoding#structure
     */
    final int key;

    Field(int key) {
      this(key >>> 3, key & (1 << 3) - 1, key);
    }

    Field(int fieldNumber, int wireType, int key) {
      this.fieldNumber = fieldNumber;
      this.wireType = wireType;
      this.key = key;
    }

    static int fieldNumber(int key, int byteL) {
      int fieldNumber = key >>> 3;
      if (fieldNumber != 0) return fieldNumber;
      throw new IllegalArgumentException("Malformed: fieldNumber was zero at byte " + byteL);
    }

    static int wireType(int key, int byteL) {
      int wireType = key & (1 << 3) - 1;
      if (wireType != 0 && wireType != 1 && wireType != 2 && wireType != 5) {
        throw new IllegalArgumentException(
          "Malformed: invalid wireType " + wireType + " at byte " + byteL);
      }
      return wireType;
    }

    static boolean skipValue(ReadBuffer buffer, int wireType) {
      int remaining = buffer.available();
      switch (wireType) {
        case WIRETYPE_VARINT:
          for (int i = 0; i < remaining; i++) {
            if (buffer.readByte() >= 0) return true;
          }

View on GitHub (pinned to 878ce2a1fa)

Solutions

  1. Check the cause chain: an earlier decode error usually preceded this; look at the reported byte offset and dump the bytes around it.
  2. Verify the payload starts with a valid length-delimited field key (0x0a for field 1, e.g.) and that the producer uses zipkin2.proto3 Span encoding.
  3. Strip framing/padding bugs (extra NUL bytes, length prefixes applied twice) at the producer.
  4. Round-trip test: SpanBytesEncoder.PROTO3.encode(span) then decode, to confirm your pipeline handles well-formed proto3.

Example fix

// before
byte[] payload = message.getBody(); // raw bytes from a queue
Span span = SpanBytesDecoder.PROTO3.decodeOne(payload);

// after
byte[] payload = message.getBody();
if (payload.length == 0 || payload[0] == 0) {
  throw new IllegalArgumentException("payload is not proto3 (leading zero/NUL byte)");
}
Span span = SpanBytesDecoder.PROTO3.decodeOne(payload);
Defensive patterns

Strategy: validation

Validate before calling

// cheap sanity check: a zipkin proto3 span list starts with field-1 length-delimited tag 0x0a
boolean looksLikeZipkinProto3(byte[] b) { return b.length > 2 && b[0] == 0x0a; }

Try / catch

catch (IllegalArgumentException e) { if (e.getMessage().contains("fieldNumber was zero")) dropAsNonProto3(payload); else throw e; }

Prevention

When it happens

Trigger: PROTO3 decoding of bytes where a tag varint decodes to 0 (e.g. leading zero bytes) or where the stream has drifted out of sync — typically after an earlier field was mis-skipped, or when raw non-proto bytes are fed to Proto3SpanReader.

Common situations: Payload prefixed/padded with zero bytes; JSON bytes sent to a proto3 endpoint; an earlier unknown field with a bad length shifted the reader so the next 'tag' lands mid-value; manually constructed test fixtures with wrong tag bytes.

Understand the failure class

Related errors


AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14). Data as JSON: /api/errors/cd7b278474c470d9. Report an issue: GitHub.