Google Protocol Buffers - Missing required fields even though all the fields are apparently present

10

I'm trying to send a protocol buffer message over TCP, but on the receiving side I'm getting a "Missing required fields" error when trying to parse, even though apparently all the fields are there. I'm sending a 4 byte header before the message that contains the length of the message.

Here is the message definition:

message ReplayRequest {
  required string channel = 1;
  required uint32 start = 2;
  required uint32 end = 3;
}

On the client side I'm encoding the header and serializing the message into a vector.

ReplayRequest req;
req.set_channel( "channel" )
req.set_start( 1 );
req.set_end( 5 );
int byte_size = req.ByteSize();
std::vector<uint8_t> write_buffer( HEADER_SIZE + byte_size );
encode_header( ... );
req.SerializeToArray( &write_buffer[HEADER_SIZE], byte_size );

This is a hex print of the resulting buffer, where the first 4 bytes are the encoded message length (13 bytes).

00 00 00 0d 0a 07 63 68 61 6e 6e 65 6c 10 01 18 05

On the server side, I receive the header, decode it and then receive N bytes where N is the message size reported in the header. The buffer in the server with the header removed is:

0a 07 63 68 61 6e 6e 65 6c 10 01 18 05

Which is exactly the same as the one encoded client side minus the header, but when I try to ParseFromArray this buffer I get an error:

libprotobuf ERROR c:\umdf_runtime\protobuf-2.4.1\src\google\protobuf\message_lit
e.cc:123] Can't parse message of type "ReplayRequest" because it is missing 
required fields: channel, start, end

While debugging I noticed that the point where decoding fails is on this part of the protobuf generated code:

bool ReplayRequest::IsInitialized() const {
  if ((_has_bits_[0] & 0x00000007) != 0x00000007) return false;

  return true;
}

has_bits_ is being read as zero on the server side for some reason but I can't figure out why.

Any ideas?

I'm using boost::asio for the network part if it matters.

Update

As requested I'm posting the code that calls parseFromArray.

request_.ParseFromArray( &data_buffer_, data_buffer_.size() );

request_ is a ReplayRequest member variable, up until this call nothing is done to it.

data_buffer_ is a vector<uint8_t> where the TCP data is received into.

I confirmed that it is correctly sized at 13 bytes and this is its hex dump, which is the same that I get when I dump the buffer client side after serializing.

0a 07 63 68 61 6e 6e 65 6c 10 01 18 05

Update 2

I am able to parse the buffer into another instance of ReplayRequest on the client side, i.e.:

...snip...
req.SerializeToArray( &write_buffer[HEADER_SIZE], byte_size );
ReplayRequest test;
test.ParseFromArray( &write_buffer[HEADER_SIZE], byte_size );

test is successfully populated with the correct fields.

c++
boost-asio
protocol-buffers
asked on Stack Overflow Dec 18, 2012 by indiosmo • edited Dec 18, 2012 by indiosmo

2 Answers

6

The issue is that you're passing in a pointer to the vector and not a pointer to the vectors data.

instead of
request_.ParseFromArray( &data_buffer_, data_buffer_.size() );

try
request_.ParseFromArray( &data_buffer_[0], data_buffer_.size() );

answered on Stack Overflow Dec 18, 2012 by g19fanatic
1

Another solution if the required field is missing but not needed for you and if you cannot change that field to optional in the protofile, you could use ParsePartialFromArray instead of ParseFromArray.

See protobuf documentation: https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.message_lite

answered on Stack Overflow Oct 30, 2018 by gguen

User contributions licensed under CC BY-SA 3.0