vectordotdev/vector · error · LinesCodecError::Io

InvalidData

InvalidData

Error message

Unable to decode message len as number

What it means

The octet-counting framer (RFC 6587 style, `"<digits> <payload>"`) parses the ASCII digits before the space as the message length. If those bytes are not valid UTF-8 digits that parse as a `usize`, it advances past them (so decoding can make progress) and returns an `InvalidData` io error wrapped in `LinesCodecError::Io`. The framing method is selected via `framing.method = "octet_counting"` on the source's decoding config.

Source

Thrown at lib/codecs/src/decoding/framing/octet_counting.rs:150

            (State::NotDiscarding, _, Some(space_pos)) if space_pos < self.other.max_length() => {
                // Everything looks good.
                //
                // We aren't discarding, we have a space that is not beyond our
                // maximum length. Attempt to parse the bytes as a number which
                // will hopefully give us a sensible length for our message.
                let len: usize = match std::str::from_utf8(&src[..space_pos])
                    .map_err(|_| ())
                    .and_then(|num| num.parse().map_err(|_| ()))
                {
                    Ok(len) => len,
                    Err(_) => {
                        // It was not a sensible number.
                        //
                        // Advance the buffer past the erroneous bytes to
                        // prevent us getting stuck in an infinite loop.
                        src.advance(space_pos + 1);
                        self.octet_decoding = None;
                        return Err(LinesCodecError::Io(io::Error::new(
                            io::ErrorKind::InvalidData,
                            "Unable to decode message len as number",
                        )));
                    }
                };

                let from = space_pos + 1;
                let to = from + len;

                if len > self.other.max_length() {
                    // The length is greater than we want.
                    //
                    // We need to discard the entire message.
                    self.octet_decoding = Some(State::Discarding(len));
                    src.advance(space_pos + 1);

                    Ok(None)
                } else if let Some(msg) = src.get(from..to) {

View on GitHub (pinned to 3708c39b12)

Solutions

  1. Align framing on both ends: either enable octet counting on the sender (rsyslog `omfwd` with `TCP_Framing="octet-counted"`) or switch Vector's `framing.method` to `newline_delimited`/`character_delimited`.
  2. If input is genuinely mixed, split it across two sources on separate ports with the correct framing each.
  3. Capture a few payloads to confirm whether the `<len> ` prefix is present at all before changing config.

Example fix

# before
decoding:
  framing:
    method: octet_counting
# sender emits plain newline-delimited syslog

# after
decoding:
  framing:
    method: newline_delimited
Defensive patterns

Strategy: try-catch

Try / catch

match decoder.decode(&mut src).await {
    Ok(Some(frame)) => { /* handle */ }
    Ok(None) => {}
    Err(LinesCodecError::Io(ref e)) if e.kind() == io::ErrorKind::InvalidData => {
        // framing prefix was not a number: bytes were skipped, keep reading
        warn!(error = %e, "skipping non-octet-counted frame");
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Data arriving on a port/framing set to octet_counting that does not start with `<len> ` — e.g. syslog sent without the octet-counting prefix (newline-delimited BSD syslog), a leading newline/space, a negative or oversized number, or a length containing separators like commas.

Common situations: Sender set to `syslog.frame_type = "non_transparent_framing"` (newline) while Vector expects octet counting; sending plain text lines to an octet_counting input; non-ASCII bytes at datagram start (binary protocols on a reused port).

Understand the failure class

Related errors


AI-assisted analysis of vectordotdev/vector@3708c39b12 (2026-08-20). Data as JSON: /api/errors/245c9f0bee8f4d10. Report an issue: GitHub.