vectordotdev/vector · error · ChunkedGelfDecoderError::InvalidTotalChunks

Received chunk with message id

Error message

Received chunk with message id {message_id} and sequence number {sequence_number} has an invalid total chunks value of {total_chunks}. It must be between 1 and {GELF_MAX_TOTAL_CHUNKS}.

What it means

In the GELF chunking protocol, byte 9 of the chunk header is the total number of chunks for the message and must be between 1 and `GELF_MAX_TOTAL_CHUNKS` (128). `decode_chunk` validates this after reading the header and rejects chunks whose total is 0 or exceeds the max, embedding the message id, sequence number, and offending value in the error. A zero or oversized total cannot correspond to a valid GELF chunked message.

Solutions

  1. Fix the sender so the total chunks byte is a 1-based count between 1 and 128, as per the GELF chunking spec.
  2. Verify which client produces these packets (message id in the error identifies the stream) and update or fix its chunking code.
  3. Confirm chunks aren't being corrupted in transit — recompute/compare on a packet capture.
  4. Ensure only GELF-speaking senders target this UDP port.

Example fix

// before: 0-based total
chunk[9] = total_chunks as u8;            // 0 for single chunk -> error

// after: 1-based count per GELF spec
chunk[9] = total_chunks.max(1) as u8;     // e.g. 1 for a single chunk
Defensive patterns

Strategy: validation

Validate before calling

// sender-side guard
let total_chunks = parts.len() as u8;
assert!(total_chunks >= 1 && total_chunks <= 128,
        "GELF total chunks must be 1..=128, got {total_chunks}");
chunk_header[9] = total_chunks;

Try / catch

match framing.decode(&datagram) {
    Err(e) if e.to_string().contains("invalid total chunks") => {
        error!("malformed GELF sender detected: {e}");
    }
    other => { /* handle normally */ }
}

Prevention

When it happens

Trigger: A datagram passes the 10-byte length check but its third header byte (`get_u8` for total_chunks) is 0 or greater than 128 — i.e. malformed data from the sender or bit corruption in transit.

Common situations: A buggy custom client writing total chunks as a 16-bit or 0-based count; corrupted UDP payload in flight; a non-GELF protocol incidentally producing a 10+ byte datagram that lands on the chunked GELF listener.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16). Data as JSON: /api/errors/294cf9a4100cf4d3. Report an issue: GitHub.

Appendix: source

Thrown at lib/codecs/src/decoding/framing/chunked_gelf.rs:418

        // | 64 bits    | 8 bits          | 8 bits       | remaining bits       |
        // +------------+-----------------+--------------+----------------------+
        //
        // As this codec is oriented for UDP, the chunks (datagrams) are not guaranteed to be received in order,
        // nor to be received at all. So, we have to store the chunks in a buffer (state field) until we receive
        // all the chunks of a message. When we receive all the chunks of a message, we can concatenate them
        // and return the complete payload.

        // We need 10 bytes to read the message id, sequence number and total chunks
        ensure!(
            chunk.remaining() >= 10,
            InvalidChunkHeaderSnafu { header: chunk }
        );

        let message_id = chunk.get_u64();
        let sequence_number = chunk.get_u8();
        let total_chunks = chunk.get_u8();

        ensure!(
            total_chunks > 0 && total_chunks <= GELF_MAX_TOTAL_CHUNKS,
            InvalidTotalChunksSnafu {
                message_id,
                sequence_number,
                total_chunks
            }
        );

        ensure!(
            sequence_number < total_chunks,
            InvalidSequenceNumberSnafu {
                message_id,
                sequence_number,
                total_chunks
            }
        );

        let chunk_len = chunk.len();

View on GitHub (pinned to bdb87aeaa4)