vectordotdev/vector · error · ChunkedGelfDecoderError::InvalidChunkHeader

Invalid chunk header with less than 10 bytes: 0x

Error message

Invalid chunk header with less than 10 bytes: 0x{header:0x}

What it means

The GELF chunked framing decoder needs at least 10 bytes per chunk: an 8-byte message id, a 1-byte sequence number, and a 1-byte total-chunks count. If a received datagram has fewer than 10 remaining bytes, `decode_chunk` rejects it via `InvalidChunkHeaderSnafu` including the chunk contents in hex. This guards the subsequent `get_u64`/`get_u8` reads from underflowing the buffer.

Solutions

  1. Verify the sender chunks messages per the GELF spec (chunk only when payload exceeds the chunk size) — a sub-10-byte datagram is not a valid chunk header.
  2. If messages are meant to be unchunked, reconfigure the source to use plain GELF framing instead of chunked GELF.
  3. Capture packets (tcpdump/Wireshark) to identify the source of truncated or non-GELF datagrams and fix the upstream client.
  4. Check network path for MTU/fragmentation issues that could truncate UDP payloads.

Example fix

# before: sender always chunks even tiny messages
send_udp(gelf_bytes)  # 8 bytes -> error

# after: only chunk large messages
if gelf_bytes.len() > CHUNK_SIZE { send_chunked(gelf_bytes) } else { send_udp(gelf_bytes) }
Defensive patterns

Strategy: validation

Validate before calling

// sender-side guard: only chunk messages that exceed the chunk size
if payload.len() < 10 || payload.len() <= CHUNK_SIZE {
    // do not use chunked framing for tiny/unchunked messages
    send_unchunked(payload);
}

Try / catch

match framing.decode(&datagram) {
    Err(e) if e.to_string().contains("Invalid chunk header") => {
        warn!("dropping non-chunked/truncated GELF datagram ({} bytes)", datagram.len());
    }
    other => { /* handle normally */ }
}

Prevention

When it happens

Trigger: A UDP datagram passed to decode_message/decode_chunk contains fewer than 10 bytes — e.g. a truncated packet, a GELF message sent unchunked but routed to the chunked decoder, or a corrupted/empty datagram.

Common situations: A sender emitting small GELF payloads without chunking them (GELF spec says messages under ~8KB should not be chunked) while the source is configured with chunked GELF framing; MTU truncation or packet corruption on the network; a non-GELF sender hitting the GELF UDP port.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

    pub fn decode_chunk(
        &mut self,
        mut chunk: Bytes,
    ) -> Result<Option<Bytes>, ChunkedGelfDecoderError> {
        // Encoding scheme:
        //
        // +------------+-----------------+--------------+----------------------+
        // | Message id | Sequence number | Total chunks |    Chunk payload     |
        // +------------+-----------------+--------------+----------------------+
        // | 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!(

View on GitHub (pinned to bdb87aeaa4)