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

11,537

Solution 1

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() );

Solution 2

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

Share:
11,537
indiosmo
Author by

indiosmo

Updated on July 20, 2022

Comments

  • indiosmo
    indiosmo almost 2 years

    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.

  • indiosmo
    indiosmo over 11 years
    That's it. I received into a single buffer on the server before, so &data_buffer_[HEADER_SIZE] was working fine. After I split the buffers I removed the accessor. Thank you.