risingwavelabs/risingwave · error
The proto payload is empty
Error message
The proto payload is empty
What it means
`resolve_pb_header` uses the encoded proto header to compute field-index offsets (Confluent wire format navigation). If header resolution yields no remaining payload bytes, there is nothing to decode, so the function bails. This indicates a malformed or empty protobuf message body rather than a schema problem.
Source
Thrown at src/connector/src/parser/protobuf/parser.rs:222
/// | 0 | 1-4 | 5-x | x+1-end
/// | magic-byte | schema-id | message-indexes | protobuf-payload
pub(crate) fn resolve_pb_header(payload: &[u8]) -> ConnectorResult<&[u8]> {
// there's a message index array at the front of payload
// if it is the first message in proto def, the array is just and `0`
let (_, remained) = extract_schema_id(payload)?;
// The message indexes are encoded as int using variable-length zig-zag encoding,
// prefixed by the length of the array.
// Note that if the first byte is 0, it is equivalent to (1, 0) as an optimization.
match remained.first() {
Some(0) => Ok(&remained[1..]),
Some(_) => {
let (index_len, mut offset) = decode_varint_zigzag(remained)?;
for _ in 0..index_len {
offset += decode_varint_zigzag(&remained[offset..])?.1;
}
Ok(&remained[offset..])
}
None => bail!("The proto payload is empty"),
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_decode_varint_zigzag() {
// 1. Positive number
let buffer = vec![0x02];
let (value, len) = decode_varint_zigzag(&buffer).unwrap();
assert_eq!(value, 1);
assert_eq!(len, 1);
// 2. Negative number
let buffer = vec![0x01];
let (value, len) = decode_varint_zigzag(&buffer).unwrap();View on GitHub (pinned to 6469eb736d)
Solutions
- Filter out empty/tombstone messages upstream or enable tombstone handling so empty payloads are skipped.
- Verify the producer is publishing valid non-empty protobuf bytes.
- Check you are reading the correct topic/partition with actual protobuf-encoded records.
- Add a payload-size/type check in the producing application before send.
Example fix
// before: producer sends empty payload
producer.send(record_with(b""));
// after: skip tombstones
if payload.is_empty() { return Ok(()); } Defensive patterns
Strategy: try-catch
Validate before calling
// Producer-side guard before publishing:
if payload.is_empty() { return Err("refusing to publish empty protobuf payload"); } Try / catch
match decode_record(bytes) {
Err(e) if e.to_string().contains("The proto payload is empty") => {
// treat as tombstone: skip or emit a delete marker
Ok(None)
}
other => other,
} Prevention
- Skip or handle Kafka tombstone records (null values) in sources.
- Validate payloads are non-empty in the producing application.
- Verify the topic actually contains protobuf-encoded records.
When it happens
Trigger: Called from `generate_accessor` while building the protobuf accessor; fires when the remaining payload slice after varint index navigation is `None` — i.e. the message bytes are empty (zero-length Kafka value) or nothing remains after the header.
Common situations: Kafka topic contains tombstone records (null/empty values) with protobuf encoding; a producer publishing empty payloads by misconfiguration; compacted-topic cleanup sending empty bodies; reading the wrong topic where records are not protobuf-encoded.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- protobuf key is not supported
- failed to parse message indexes
- query_epoch not set in distributed lookup join
- unspecified AsOf join inequality type
- no chunk in IngestDmlPayloadRequest
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/657cfa32ce35ffc8.
Report an issue: GitHub.