vectordotdev/vector · error · LinesCodecError
Unable to decode message len as number
Error message
Unable to decode message len as number
What it means
The octet counting framer reads a leading decimal length prefix followed by a space. This error is raised when the bytes before the first space cannot be parsed as a valid number (the length prefix is not a sensible integer), so the framer cannot determine the message length. The parser advances past the bad bytes to avoid an infinite loop.
Solutions
- Fix the sender to emit the octet-counting format: ASCII decimal byte count, one space, then the payload.
- Change the Vector source's framing to match the actual sender format (e.g. newline_delimited).
- Inspect what is actually arriving on the socket (tcpdump/tcpreceive) to identify the mismatch.
Example fix
// before (sender) "hello world\n" // after (octet counting) "11 hello world"
Defensive patterns
Strategy: validation
Validate before calling
// verify sender emits octet counting format before shipping
fn looks_like_octet_frame(buf: &[u8]) -> bool {
match buf.iter().position(|&b| b == b' ') {
Some(sp) => buf[..sp].iter().all(|b| b.is_ascii_digit()),
None => false,
}
} Try / catch
match framed_stream.next().await {
Err(e) if e.kind() == ErrorKind::InvalidData => {
// wrong framing: log a sample of raw bytes and reconfigure
}
other => other?,
} Prevention
- Match producer framing to consumer framing config explicitly.
- Send a known test frame (<len> SP <payload>) during deploy validation.
- Never point plain-line senders at octet-counting consumers.
When it happens
Trigger: Sending data over a TCP stream whose first token is not a decimal length followed by a space; a sender using a different framing protocol (e.g. newline-delimited or syslog) pointed at an octet-counting configured source; corrupted/partial data at the start of the stream.
Common situations: Mixing up framing configs between producers and consumers (producer sends plain lines, consumer expects <len> SP <message>); binary or garbage data hitting the port; a load balancer injecting non-protocol data.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Unable to decode message as UTF8
- Invalid chunk header with less than 10 bytes: 0x
- InvalidData
- Received chunk with message id
- Received chunk with message id
AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16).
Data as JSON: /api/errors/d22658c3d6a39a44.
Report an issue: GitHub.
Appendix: 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 bdb87aeaa4)