vectordotdev/vector · error · ChunkedGelfDecoderError

Received chunk with message id {message_id} and sequence num

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 a chunked GELF datagram, the byte after the sequence number declares the total number of chunks for the message, and it must be between 1 and GELF_MAX_TOTAL_CHUNKS (128). If the byte is 0 or greater than 128, `InvalidTotalChunksSnafu` rejects the chunk with this message. This guards the reassembly buffer from absurd allocation sizes driven by corrupt or hostile datagrams.

Source

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

        // | 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 mut state_lock = self.state.lock().expect("poisoned lock");

View on GitHub (pinned to 99894c8d88)

Solutions

  1. Compare the sender's chunk header layout byte-for-byte against the GELF chunking spec (8-byte id, 1-byte seq, 1-byte total).
  2. If the sender legitimately needs >128 chunks, split messages further upstream so each message fits in ≤128 chunks.
  3. Capture one failing datagram with tcpdump and hex-dump the first 10 bytes to confirm which side is wrong.
Defensive patterns

Strategy: try-catch

Try / catch

Err(e) if e.to_string().contains("invalid total chunks value") => {
    metrics.counter("gelf_bad_total_chunks", 1);
    debug!(error = %e, "discarding datagram with invalid total chunks");
}

Prevention

When it happens

Trigger: A datagram with magic `0x1e 0x0f` where the 10th byte (total chunks) is 0 or >128 — e.g. a sender that writes the count as a 16/32-bit integer instead of one byte, or arbitrary binary that collides with the magic bytes.

Common situations: Custom GELF chunker implementations that misplace the header layout; fuzzing/scanners hitting the UDP port; corrupted datagrams from a misbehaving Graylog forwarder.

Related errors


AI-assisted analysis of vectordotdev/vector@99894c8d88 (2026-08-20). Data as JSON: /api/errors/294cf9a4100cf4d3. Report an issue: GitHub.