Add length field to MoQT control messages.

PiperOrigin-RevId: 683174788
diff --git a/quiche/quic/moqt/moqt_framer.cc b/quiche/quic/moqt/moqt_framer.cc
index 074c2be..308a184 100644
--- a/quiche/quic/moqt/moqt_framer.cc
+++ b/quiche/quic/moqt/moqt_framer.cc
@@ -214,6 +214,31 @@
   return *std::move(buffer);
 }
 
+// Serializes data into buffer using the default allocator.  Invokes QUICHE_BUG
+// on failure.
+template <typename... Ts>
+QuicheBuffer SerializeControlMessage(MoqtMessageType type, Ts... data) {
+  uint64_t message_type = static_cast<uint64_t>(type);
+  size_t payload_size = quiche::ComputeLengthOnWire(data...);
+  size_t buffer_size =
+      payload_size + quiche::ComputeLengthOnWire(WireVarInt62(message_type),
+                                                 WireVarInt62(payload_size));
+  if (buffer_size == 0) {
+    return QuicheBuffer();
+  }
+
+  QuicheBuffer buffer(quiche::SimpleBufferAllocator::Get(), buffer_size);
+  quiche::QuicheDataWriter writer(buffer.size(), buffer.data());
+  absl::Status status = SerializeIntoWriter(
+      writer, WireVarInt62(message_type), WireVarInt62(payload_size), data...);
+  if (!status.ok() || writer.remaining() != 0) {
+    QUICHE_BUG(moqt_failed_serialization)
+        << "Failed to serialize MoQT frame: " << status;
+    return QuicheBuffer();
+  }
+  return buffer;
+}
+
 WireUint8 WireDeliveryOrder(std::optional<MoqtDeliveryOrder> delivery_order) {
   if (!delivery_order.has_value()) {
     return WireUint8(0x00);
@@ -372,8 +397,8 @@
     string_parameters.push_back(
         StringParameter(MoqtSetupParameter::kPath, *message.path));
   }
-  return Serialize(
-      WireVarInt62(MoqtMessageType::kClientSetup),
+  return SerializeControlMessage(
+      MoqtMessageType::kClientSetup,
       WireVarInt62(message.supported_versions.size()),
       WireSpan<WireVarInt62, MoqtVersion>(message.supported_versions),
       WireVarInt62(string_parameters.size() + int_parameters.size()),
@@ -396,10 +421,10 @@
     int_parameters.push_back(
         IntParameter(MoqtSetupParameter::kSupportObjectAcks, 1u));
   }
-  return Serialize(WireVarInt62(MoqtMessageType::kServerSetup),
-                   WireVarInt62(message.selected_version),
-                   WireVarInt62(int_parameters.size()),
-                   WireSpan<WireIntParameter>(int_parameters));
+  return SerializeControlMessage(MoqtMessageType::kServerSetup,
+                                 WireVarInt62(message.selected_version),
+                                 WireVarInt62(int_parameters.size()),
+                                 WireSpan<WireIntParameter>(int_parameters));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeSubscribe(
@@ -412,17 +437,17 @@
   switch (filter_type) {
     case MoqtFilterType::kLatestGroup:
     case MoqtFilterType::kLatestObject:
-      return Serialize(
-          WireVarInt62(MoqtMessageType::kSubscribe),
-          WireVarInt62(message.subscribe_id), WireVarInt62(message.track_alias),
+      return SerializeControlMessage(
+          MoqtMessageType::kSubscribe, WireVarInt62(message.subscribe_id),
+          WireVarInt62(message.track_alias),
           WireFullTrackName(message.full_track_name, true),
           WireUint8(message.subscriber_priority),
           WireDeliveryOrder(message.group_order), WireVarInt62(filter_type),
           WireSubscribeParameterList(message.parameters));
     case MoqtFilterType::kAbsoluteStart:
-      return Serialize(
-          WireVarInt62(MoqtMessageType::kSubscribe),
-          WireVarInt62(message.subscribe_id), WireVarInt62(message.track_alias),
+      return SerializeControlMessage(
+          MoqtMessageType::kSubscribe, WireVarInt62(message.subscribe_id),
+          WireVarInt62(message.track_alias),
           WireFullTrackName(message.full_track_name, true),
           WireUint8(message.subscriber_priority),
           WireDeliveryOrder(message.group_order), WireVarInt62(filter_type),
@@ -430,9 +455,9 @@
           WireVarInt62(*message.start_object),
           WireSubscribeParameterList(message.parameters));
     case MoqtFilterType::kAbsoluteRange:
-      return Serialize(
-          WireVarInt62(MoqtMessageType::kSubscribe),
-          WireVarInt62(message.subscribe_id), WireVarInt62(message.track_alias),
+      return SerializeControlMessage(
+          MoqtMessageType::kSubscribe, WireVarInt62(message.subscribe_id),
+          WireVarInt62(message.track_alias),
           WireFullTrackName(message.full_track_name, true),
           WireUint8(message.subscriber_priority),
           WireDeliveryOrder(message.group_order), WireVarInt62(filter_type),
@@ -454,49 +479,49 @@
         << "SUBSCRIBE_OK with delivery timeout";
   }
   if (message.largest_id.has_value()) {
-    return Serialize(WireVarInt62(MoqtMessageType::kSubscribeOk),
-                     WireVarInt62(message.subscribe_id),
-                     WireVarInt62(message.expires.ToMilliseconds()),
-                     WireDeliveryOrder(message.group_order), WireUint8(1),
-                     WireVarInt62(message.largest_id->group),
-                     WireVarInt62(message.largest_id->object),
-                     WireSubscribeParameterList(message.parameters));
+    return SerializeControlMessage(
+        MoqtMessageType::kSubscribeOk, WireVarInt62(message.subscribe_id),
+        WireVarInt62(message.expires.ToMilliseconds()),
+        WireDeliveryOrder(message.group_order), WireUint8(1),
+        WireVarInt62(message.largest_id->group),
+        WireVarInt62(message.largest_id->object),
+        WireSubscribeParameterList(message.parameters));
   }
-  return Serialize(WireVarInt62(MoqtMessageType::kSubscribeOk),
-                   WireVarInt62(message.subscribe_id),
-                   WireVarInt62(message.expires.ToMilliseconds()),
-                   WireDeliveryOrder(message.group_order), WireUint8(0),
-                   WireSubscribeParameterList(message.parameters));
+  return SerializeControlMessage(
+      MoqtMessageType::kSubscribeOk, WireVarInt62(message.subscribe_id),
+      WireVarInt62(message.expires.ToMilliseconds()),
+      WireDeliveryOrder(message.group_order), WireUint8(0),
+      WireSubscribeParameterList(message.parameters));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeSubscribeError(
     const MoqtSubscribeError& message) {
-  return Serialize(WireVarInt62(MoqtMessageType::kSubscribeError),
-                   WireVarInt62(message.subscribe_id),
-                   WireVarInt62(message.error_code),
-                   WireStringWithVarInt62Length(message.reason_phrase),
-                   WireVarInt62(message.track_alias));
+  return SerializeControlMessage(
+      MoqtMessageType::kSubscribeError, WireVarInt62(message.subscribe_id),
+      WireVarInt62(message.error_code),
+      WireStringWithVarInt62Length(message.reason_phrase),
+      WireVarInt62(message.track_alias));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeUnsubscribe(
     const MoqtUnsubscribe& message) {
-  return Serialize(WireVarInt62(MoqtMessageType::kUnsubscribe),
-                   WireVarInt62(message.subscribe_id));
+  return SerializeControlMessage(MoqtMessageType::kUnsubscribe,
+                                 WireVarInt62(message.subscribe_id));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeSubscribeDone(
     const MoqtSubscribeDone& message) {
   if (message.final_id.has_value()) {
-    return Serialize(WireVarInt62(MoqtMessageType::kSubscribeDone),
-                     WireVarInt62(message.subscribe_id),
-                     WireVarInt62(message.status_code),
-                     WireStringWithVarInt62Length(message.reason_phrase),
-                     WireUint8(1), WireVarInt62(message.final_id->group),
-                     WireVarInt62(message.final_id->object));
+    return SerializeControlMessage(
+        MoqtMessageType::kSubscribeDone, WireVarInt62(message.subscribe_id),
+        WireVarInt62(message.status_code),
+        WireStringWithVarInt62Length(message.reason_phrase), WireUint8(1),
+        WireVarInt62(message.final_id->group),
+        WireVarInt62(message.final_id->object));
   }
-  return Serialize(
-      WireVarInt62(MoqtMessageType::kSubscribeDone),
-      WireVarInt62(message.subscribe_id), WireVarInt62(message.status_code),
+  return SerializeControlMessage(
+      MoqtMessageType::kSubscribeDone, WireVarInt62(message.subscribe_id),
+      WireVarInt62(message.status_code),
       WireStringWithVarInt62Length(message.reason_phrase), WireUint8(0));
 }
 
@@ -514,11 +539,11 @@
     QUICHE_BUG(MoqtFramer_invalid_subscribe_update) << "Invalid object range";
     return quiche::QuicheBuffer();
   }
-  return Serialize(
-      WireVarInt62(MoqtMessageType::kSubscribeUpdate),
-      WireVarInt62(message.subscribe_id), WireVarInt62(message.start_group),
-      WireVarInt62(message.start_object), WireVarInt62(end_group),
-      WireVarInt62(end_object), WireUint8(message.subscriber_priority),
+  return SerializeControlMessage(
+      MoqtMessageType::kSubscribeUpdate, WireVarInt62(message.subscribe_id),
+      WireVarInt62(message.start_group), WireVarInt62(message.start_object),
+      WireVarInt62(end_group), WireVarInt62(end_object),
+      WireUint8(message.subscriber_priority),
       WireSubscribeParameterList(message.parameters));
 }
 
@@ -527,101 +552,110 @@
   if (message.parameters.delivery_timeout.has_value()) {
     QUICHE_BUG(MoqtFramer_invalid_announce) << "ANNOUNCE with delivery timeout";
   }
-  return Serialize(
-      WireVarInt62(static_cast<uint64_t>(MoqtMessageType::kAnnounce)),
+  return SerializeControlMessage(
+      MoqtMessageType::kAnnounce,
       WireFullTrackName(message.track_namespace, false),
       WireSubscribeParameterList(message.parameters));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeAnnounceOk(
     const MoqtAnnounceOk& message) {
-  return Serialize(WireVarInt62(MoqtMessageType::kAnnounceOk),
-                   WireFullTrackName(message.track_namespace, false));
+  return SerializeControlMessage(
+      MoqtMessageType::kAnnounceOk,
+      WireFullTrackName(message.track_namespace, false));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeAnnounceError(
     const MoqtAnnounceError& message) {
-  return Serialize(WireVarInt62(MoqtMessageType::kAnnounceError),
-                   WireFullTrackName(message.track_namespace, false),
-                   WireVarInt62(message.error_code),
-                   WireStringWithVarInt62Length(message.reason_phrase));
+  return SerializeControlMessage(
+      MoqtMessageType::kAnnounceError,
+      WireFullTrackName(message.track_namespace, false),
+      WireVarInt62(message.error_code),
+      WireStringWithVarInt62Length(message.reason_phrase));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeAnnounceCancel(
     const MoqtAnnounceCancel& message) {
-  return Serialize(WireVarInt62(MoqtMessageType::kAnnounceCancel),
-                   WireFullTrackName(message.track_namespace, false),
-                   WireVarInt62(message.error_code),
-                   WireStringWithVarInt62Length(message.reason_phrase));
+  return SerializeControlMessage(
+      MoqtMessageType::kAnnounceCancel,
+      WireFullTrackName(message.track_namespace, false),
+      WireVarInt62(message.error_code),
+      WireStringWithVarInt62Length(message.reason_phrase));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeTrackStatusRequest(
     const MoqtTrackStatusRequest& message) {
-  return Serialize(WireVarInt62(MoqtMessageType::kTrackStatusRequest),
-                   WireFullTrackName(message.full_track_name, true));
+  return SerializeControlMessage(
+      MoqtMessageType::kTrackStatusRequest,
+      WireFullTrackName(message.full_track_name, true));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeUnannounce(
     const MoqtUnannounce& message) {
-  return Serialize(WireVarInt62(MoqtMessageType::kUnannounce),
-                   WireFullTrackName(message.track_namespace, false));
+  return SerializeControlMessage(
+      MoqtMessageType::kUnannounce,
+      WireFullTrackName(message.track_namespace, false));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeTrackStatus(
     const MoqtTrackStatus& message) {
-  return Serialize(WireVarInt62(MoqtMessageType::kTrackStatus),
-                   WireFullTrackName(message.full_track_name, true),
-                   WireVarInt62(message.status_code),
-                   WireVarInt62(message.last_group),
-                   WireVarInt62(message.last_object));
+  return SerializeControlMessage(
+      MoqtMessageType::kTrackStatus,
+      WireFullTrackName(message.full_track_name, true),
+      WireVarInt62(message.status_code), WireVarInt62(message.last_group),
+      WireVarInt62(message.last_object));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeGoAway(const MoqtGoAway& message) {
-  return Serialize(WireVarInt62(MoqtMessageType::kGoAway),
-                   WireStringWithVarInt62Length(message.new_session_uri));
+  return SerializeControlMessage(
+      MoqtMessageType::kGoAway,
+      WireStringWithVarInt62Length(message.new_session_uri));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeSubscribeNamespace(
     const MoqtSubscribeNamespace& message) {
-  return Serialize(WireVarInt62(MoqtMessageType::kSubscribeNamespace),
-                   WireFullTrackName(message.track_namespace, false),
-                   WireSubscribeParameterList(message.parameters));
+  return SerializeControlMessage(
+      MoqtMessageType::kSubscribeNamespace,
+      WireFullTrackName(message.track_namespace, false),
+      WireSubscribeParameterList(message.parameters));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeSubscribeNamespaceOk(
     const MoqtSubscribeNamespaceOk& message) {
-  return Serialize(WireVarInt62(MoqtMessageType::kSubscribeNamespaceOk),
-                   WireFullTrackName(message.track_namespace, false));
+  return SerializeControlMessage(
+      MoqtMessageType::kSubscribeNamespaceOk,
+      WireFullTrackName(message.track_namespace, false));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeSubscribeNamespaceError(
     const MoqtSubscribeNamespaceError& message) {
-  return Serialize(WireVarInt62(MoqtMessageType::kSubscribeNamespaceError),
-                   WireFullTrackName(message.track_namespace, false),
-                   WireVarInt62(message.error_code),
-                   WireStringWithVarInt62Length(message.reason_phrase));
+  return SerializeControlMessage(
+      MoqtMessageType::kSubscribeNamespaceError,
+      WireFullTrackName(message.track_namespace, false),
+      WireVarInt62(message.error_code),
+      WireStringWithVarInt62Length(message.reason_phrase));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeUnsubscribeNamespace(
     const MoqtUnsubscribeNamespace& message) {
-  return Serialize(WireVarInt62(MoqtMessageType::kUnsubscribeNamespace),
-                   WireFullTrackName(message.track_namespace, false));
+  return SerializeControlMessage(
+      MoqtMessageType::kUnsubscribeNamespace,
+      WireFullTrackName(message.track_namespace, false));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeMaxSubscribeId(
     const MoqtMaxSubscribeId& message) {
-  return Serialize(WireVarInt62(MoqtMessageType::kMaxSubscribeId),
-                   WireVarInt62(message.max_subscribe_id));
+  return SerializeControlMessage(MoqtMessageType::kMaxSubscribeId,
+                                 WireVarInt62(message.max_subscribe_id));
 }
 
 quiche::QuicheBuffer MoqtFramer::SerializeObjectAck(
     const MoqtObjectAck& message) {
-  return Serialize(WireVarInt62(MoqtMessageType::kObjectAck),
-                   WireVarInt62(message.subscribe_id),
-                   WireVarInt62(message.group_id),
-                   WireVarInt62(message.object_id),
-                   WireVarInt62(SignedVarintSerializedForm(
-                       message.delta_from_deadline.ToMicroseconds())));
+  return SerializeControlMessage(
+      MoqtMessageType::kObjectAck, WireVarInt62(message.subscribe_id),
+      WireVarInt62(message.group_id), WireVarInt62(message.object_id),
+      WireVarInt62(SignedVarintSerializedForm(
+          message.delta_from_deadline.ToMicroseconds())));
 }
 
 // static
diff --git a/quiche/quic/moqt/moqt_framer_test.cc b/quiche/quic/moqt/moqt_framer_test.cc
index 5ed05c1..2446a8f 100644
--- a/quiche/quic/moqt/moqt_framer_test.cc
+++ b/quiche/quic/moqt/moqt_framer_test.cc
@@ -409,7 +409,7 @@
           }
           buffer = framer_.SerializeSubscribe(subscribe);
           // Go to the filter type.
-          const uint8_t* read = BufferAtOffset(buffer, 15);
+          const uint8_t* read = BufferAtOffset(buffer, 16);
           EXPECT_EQ(static_cast<MoqtFilterType>(*read), expected_filter_type);
           EXPECT_GT(buffer.size(), 0);
           if (expected_filter_type == MoqtFilterType::kAbsoluteRange &&
@@ -480,7 +480,7 @@
   quiche::QuicheBuffer buffer;
   buffer = framer_.SerializeSubscribeUpdate(subscribe_update);
   EXPECT_GT(buffer.size(), 0);
-  const uint8_t* end_group = BufferAtOffset(buffer, 4);
+  const uint8_t* end_group = BufferAtOffset(buffer, 5);
   EXPECT_EQ(*end_group, 5);
   const uint8_t* end_object = end_group + 1;
   EXPECT_EQ(*end_object, 0);
@@ -500,7 +500,7 @@
   quiche::QuicheBuffer buffer;
   buffer = framer_.SerializeSubscribeUpdate(subscribe_update);
   EXPECT_GT(buffer.size(), 0);
-  const uint8_t* end_group = BufferAtOffset(buffer, 4);
+  const uint8_t* end_group = BufferAtOffset(buffer, 5);
   EXPECT_EQ(*end_group, 5);
   const uint8_t* end_object = end_group + 1;
   EXPECT_EQ(*end_object, 7);
diff --git a/quiche/quic/moqt/moqt_parser.cc b/quiche/quic/moqt/moqt_parser.cc
index 2140748..9fea89c 100644
--- a/quiche/quic/moqt/moqt_parser.cc
+++ b/quiche/quic/moqt/moqt_parser.cc
@@ -189,61 +189,94 @@
 }
 
 size_t MoqtControlParser::ProcessMessage(absl::string_view data) {
-  uint64_t value;
+  uint64_t value, length;
   quic::QuicDataReader reader(data);
-  if (!reader.ReadVarInt62(&value)) {
+  if (!reader.ReadVarInt62(&value) || !reader.ReadVarInt62(&length)) {
+    return 0;
+  }
+  if (length > reader.BytesRemaining()) {
     return 0;
   }
   auto type = static_cast<MoqtMessageType>(value);
+  size_t message_header_length = reader.PreviouslyReadPayload().length();
+  size_t bytes_read;
   switch (type) {
     case MoqtMessageType::kClientSetup:
-      return ProcessClientSetup(reader);
+      bytes_read = ProcessClientSetup(reader);
+      break;
     case MoqtMessageType::kServerSetup:
-      return ProcessServerSetup(reader);
+      bytes_read = ProcessServerSetup(reader);
+      break;
     case MoqtMessageType::kSubscribe:
-      return ProcessSubscribe(reader);
+      bytes_read = ProcessSubscribe(reader);
+      break;
     case MoqtMessageType::kSubscribeOk:
-      return ProcessSubscribeOk(reader);
+      bytes_read = ProcessSubscribeOk(reader);
+      break;
     case MoqtMessageType::kSubscribeError:
-      return ProcessSubscribeError(reader);
+      bytes_read = ProcessSubscribeError(reader);
+      break;
     case MoqtMessageType::kUnsubscribe:
-      return ProcessUnsubscribe(reader);
+      bytes_read = ProcessUnsubscribe(reader);
+      break;
     case MoqtMessageType::kSubscribeDone:
-      return ProcessSubscribeDone(reader);
+      bytes_read = ProcessSubscribeDone(reader);
+      break;
     case MoqtMessageType::kSubscribeUpdate:
-      return ProcessSubscribeUpdate(reader);
+      bytes_read = ProcessSubscribeUpdate(reader);
+      break;
     case MoqtMessageType::kAnnounce:
-      return ProcessAnnounce(reader);
+      bytes_read = ProcessAnnounce(reader);
+      break;
     case MoqtMessageType::kAnnounceOk:
-      return ProcessAnnounceOk(reader);
+      bytes_read = ProcessAnnounceOk(reader);
+      break;
     case MoqtMessageType::kAnnounceError:
-      return ProcessAnnounceError(reader);
+      bytes_read = ProcessAnnounceError(reader);
+      break;
     case MoqtMessageType::kAnnounceCancel:
-      return ProcessAnnounceCancel(reader);
+      bytes_read = ProcessAnnounceCancel(reader);
+      break;
     case MoqtMessageType::kTrackStatusRequest:
-      return ProcessTrackStatusRequest(reader);
+      bytes_read = ProcessTrackStatusRequest(reader);
+      break;
     case MoqtMessageType::kUnannounce:
-      return ProcessUnannounce(reader);
+      bytes_read = ProcessUnannounce(reader);
+      break;
     case MoqtMessageType::kTrackStatus:
-      return ProcessTrackStatus(reader);
+      bytes_read = ProcessTrackStatus(reader);
+      break;
     case MoqtMessageType::kGoAway:
-      return ProcessGoAway(reader);
+      bytes_read = ProcessGoAway(reader);
+      break;
     case MoqtMessageType::kSubscribeNamespace:
-      return ProcessSubscribeNamespace(reader);
+      bytes_read = ProcessSubscribeNamespace(reader);
+      break;
     case MoqtMessageType::kSubscribeNamespaceOk:
-      return ProcessSubscribeNamespaceOk(reader);
+      bytes_read = ProcessSubscribeNamespaceOk(reader);
+      break;
     case MoqtMessageType::kSubscribeNamespaceError:
-      return ProcessSubscribeNamespaceError(reader);
+      bytes_read = ProcessSubscribeNamespaceError(reader);
+      break;
     case MoqtMessageType::kUnsubscribeNamespace:
-      return ProcessUnsubscribeNamespace(reader);
+      bytes_read = ProcessUnsubscribeNamespace(reader);
+      break;
     case MoqtMessageType::kMaxSubscribeId:
-      return ProcessMaxSubscribeId(reader);
+      bytes_read = ProcessMaxSubscribeId(reader);
+      break;
     case moqt::MoqtMessageType::kObjectAck:
-      return ProcessObjectAck(reader);
+      bytes_read = ProcessObjectAck(reader);
+      break;
     default:
       ParseError("Unknown message type");
+      bytes_read = 0;
+      break;
   }
-  return 0;
+  if ((bytes_read - message_header_length) != length) {
+    ParseError("Message length does not match payload length");
+    return 0;
+  }
+  return bytes_read;
 }
 
 size_t MoqtControlParser::ProcessClientSetup(quic::QuicDataReader& reader) {
diff --git a/quiche/quic/moqt/moqt_parser_test.cc b/quiche/quic/moqt/moqt_parser_test.cc
index 5c1d028..4cb7c3c 100644
--- a/quiche/quic/moqt/moqt_parser_test.cc
+++ b/quiche/quic/moqt/moqt_parser_test.cc
@@ -375,6 +375,31 @@
   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
 }
 
+TEST_P(MoqtParserTest, PayloadLengthTooLong) {
+  if (IsDataStream()) {
+    return;
+  }
+  std::unique_ptr<TestMessageBase> message = MakeMessage();
+  message->IncreasePayloadLengthByOne();
+  ProcessData(message->PacketSample(), false);
+  // The parser will actually report a message, because it's all there.
+  EXPECT_EQ(visitor_.messages_received_, 1);
+  EXPECT_EQ(visitor_.parsing_error_,
+            "Message length does not match payload length");
+}
+
+TEST_P(MoqtParserTest, PayloadLengthTooShort) {
+  if (IsDataStream()) {
+    return;
+  }
+  std::unique_ptr<TestMessageBase> message = MakeMessage();
+  message->DecreasePayloadLengthByOne();
+  ProcessData(message->PacketSample(), false);
+  EXPECT_EQ(visitor_.messages_received_, 1);
+  EXPECT_EQ(visitor_.parsing_error_,
+            "Message length does not match payload length");
+}
+
 // Tests for message-specific error cases, and behaviors for a single message
 // type.
 class MoqtMessageSpecificTest : public quic::test::QuicTest {
@@ -491,10 +516,10 @@
 TEST_F(MoqtMessageSpecificTest, ClientSetupRoleIsInvalid) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char setup[] = {
-      0x40, 0x40, 0x02, 0x01, 0x02,  // versions
-      0x03,                          // 3 params
-      0x00, 0x01, 0x04,              // role = invalid
-      0x01, 0x03, 0x66, 0x6f, 0x6f   // path = "foo"
+      0x40, 0x40, 0x0c, 0x02, 0x01, 0x02,  // versions
+      0x03,                                // 3 params
+      0x00, 0x01, 0x04,                    // role = invalid
+      0x01, 0x03, 0x66, 0x6f, 0x6f         // path = "foo"
   };
   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
   EXPECT_EQ(visitor_.messages_received_, 0);
@@ -506,7 +531,7 @@
 TEST_F(MoqtMessageSpecificTest, ServerSetupRoleIsInvalid) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char setup[] = {
-      0x40, 0x41, 0x01,
+      0x40, 0x41, 0x0a, 0x01,
       0x01,                         // 1 param
       0x00, 0x01, 0x04,             // role = invalid
       0x01, 0x03, 0x66, 0x6f, 0x6f  // path = "foo"
@@ -521,11 +546,11 @@
 TEST_F(MoqtMessageSpecificTest, SetupRoleAppearsTwice) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char setup[] = {
-      0x40, 0x40, 0x02, 0x01, 0x02,  // versions
-      0x03,                          // 3 params
-      0x00, 0x01, 0x03,              // role = PubSub
-      0x00, 0x01, 0x03,              // role = PubSub
-      0x01, 0x03, 0x66, 0x6f, 0x6f   // path = "foo"
+      0x40, 0x40, 0x0f, 0x02, 0x01, 0x02,  // versions
+      0x03,                                // 3 params
+      0x00, 0x01, 0x03,                    // role = PubSub
+      0x00, 0x01, 0x03,                    // role = PubSub
+      0x01, 0x03, 0x66, 0x6f, 0x6f         // path = "foo"
   };
   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
   EXPECT_EQ(visitor_.messages_received_, 0);
@@ -537,9 +562,9 @@
 TEST_F(MoqtMessageSpecificTest, ClientSetupRoleIsMissing) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char setup[] = {
-      0x40, 0x40, 0x02, 0x01, 0x02,  // versions = 1, 2
-      0x01,                          // 1 param
-      0x01, 0x03, 0x66, 0x6f, 0x6f,  // path = "foo"
+      0x40, 0x40, 0x09, 0x02, 0x01, 0x02,  // versions = 1, 2
+      0x01,                                // 1 param
+      0x01, 0x03, 0x66, 0x6f, 0x6f,        // path = "foo"
   };
   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
   EXPECT_EQ(visitor_.messages_received_, 0);
@@ -552,12 +577,12 @@
 TEST_F(MoqtMessageSpecificTest, ClientSetupMaxSubscribeIdAppearsTwice) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char setup[] = {
-      0x40, 0x40, 0x02, 0x01, 0x02,  // versions
-      0x04,                          // 4 params
-      0x00, 0x01, 0x03,              // role = PubSub
-      0x01, 0x03, 0x66, 0x6f, 0x6f,  // path = "foo"
-      0x02, 0x01, 0x32,              // max_subscribe_id = 50
-      0x02, 0x01, 0x32,              // max_subscribe_id = 50
+      0x40, 0x40, 0x12, 0x02, 0x01, 0x02,  // versions
+      0x04,                                // 4 params
+      0x00, 0x01, 0x03,                    // role = PubSub
+      0x01, 0x03, 0x66, 0x6f, 0x6f,        // path = "foo"
+      0x02, 0x01, 0x32,                    // max_subscribe_id = 50
+      0x02, 0x01, 0x32,                    // max_subscribe_id = 50
   };
   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
   EXPECT_EQ(visitor_.messages_received_, 0);
@@ -570,7 +595,7 @@
 TEST_F(MoqtMessageSpecificTest, ServerSetupRoleIsMissing) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char setup[] = {
-      0x40, 0x41, 0x01, 0x00,  // 1 param
+      0x40, 0x41, 0x02, 0x01, 0x00,  // 1 param
   };
   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
   EXPECT_EQ(visitor_.messages_received_, 0);
@@ -583,7 +608,7 @@
 TEST_F(MoqtMessageSpecificTest, SetupRoleVarintLengthIsWrong) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char setup[] = {
-      0x40, 0x40,                   // type
+      0x40, 0x40, 0x0c,             // type
       0x02, 0x01, 0x02,             // versions
       0x02,                         // 2 parameters
       0x00, 0x02, 0x03,             // role = PubSub, but length is 2
@@ -601,7 +626,7 @@
 TEST_F(MoqtMessageSpecificTest, SetupPathFromServer) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char setup[] = {
-      0x40, 0x41,
+      0x40, 0x41, 0x07,
       0x01,                          // version = 1
       0x01,                          // 1 param
       0x01, 0x03, 0x66, 0x6f, 0x6f,  // path = "foo"
@@ -616,11 +641,11 @@
 TEST_F(MoqtMessageSpecificTest, SetupPathAppearsTwice) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char setup[] = {
-      0x40, 0x40, 0x02, 0x01, 0x02,  // versions = 1, 2
-      0x03,                          // 3 params
-      0x00, 0x01, 0x03,              // role = PubSub
-      0x01, 0x03, 0x66, 0x6f, 0x6f,  // path = "foo"
-      0x01, 0x03, 0x66, 0x6f, 0x6f,  // path = "foo"
+      0x40, 0x40, 0x11, 0x02, 0x01, 0x02,  // versions = 1, 2
+      0x03,                                // 3 params
+      0x00, 0x01, 0x03,                    // role = PubSub
+      0x01, 0x03, 0x66, 0x6f, 0x6f,        // path = "foo"
+      0x01, 0x03, 0x66, 0x6f, 0x6f,        // path = "foo"
   };
   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
   EXPECT_EQ(visitor_.messages_received_, 0);
@@ -633,10 +658,10 @@
 TEST_F(MoqtMessageSpecificTest, SetupPathOverWebtrans) {
   MoqtControlParser parser(kWebTrans, visitor_);
   char setup[] = {
-      0x40, 0x40, 0x02, 0x01, 0x02,  // versions = 1, 2
-      0x02,                          // 2 params
-      0x00, 0x01, 0x03,              // role = PubSub
-      0x01, 0x03, 0x66, 0x6f, 0x6f,  // path = "foo"
+      0x40, 0x40, 0x0b, 0x02, 0x01, 0x02,  // versions = 1, 2
+      0x02,                                // 2 params
+      0x00, 0x01, 0x03,                    // role = PubSub
+      0x01, 0x03, 0x66, 0x6f, 0x6f,        // path = "foo"
   };
   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
   EXPECT_EQ(visitor_.messages_received_, 0);
@@ -649,9 +674,9 @@
 TEST_F(MoqtMessageSpecificTest, SetupPathMissing) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char setup[] = {
-      0x40, 0x40, 0x02, 0x01, 0x02,  // versions = 1, 2
-      0x01,                          // 1 param
-      0x00, 0x01, 0x03,              // role = PubSub
+      0x40, 0x40, 0x07, 0x02, 0x01, 0x02,  // versions = 1, 2
+      0x01,                                // 1 param
+      0x00, 0x01, 0x03,                    // role = PubSub
   };
   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
   EXPECT_EQ(visitor_.messages_received_, 0);
@@ -664,12 +689,12 @@
 TEST_F(MoqtMessageSpecificTest, ServerSetupMaxSubscribeIdAppearsTwice) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char setup[] = {
-      0x40, 0x40, 0x02, 0x01, 0x02,  // versions = 1, 2
-      0x04,                          // 4 params
-      0x00, 0x01, 0x03,              // role = PubSub
-      0x01, 0x03, 0x66, 0x6f, 0x6f,  // path = "foo"
-      0x02, 0x01, 0x32,              // max_subscribe_id = 50
-      0x02, 0x01, 0x32,              // max_subscribe_id = 50
+      0x40, 0x40, 0x12, 0x02, 0x01, 0x02,  // versions = 1, 2
+      0x04,                                // 4 params
+      0x00, 0x01, 0x03,                    // role = PubSub
+      0x01, 0x03, 0x66, 0x6f, 0x6f,        // path = "foo"
+      0x02, 0x01, 0x32,                    // max_subscribe_id = 50
+      0x02, 0x01, 0x32,                    // max_subscribe_id = 50
   };
   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
   EXPECT_EQ(visitor_.messages_received_, 0);
@@ -682,8 +707,8 @@
 TEST_F(MoqtMessageSpecificTest, SubscribeAuthorizationInfoTwice) {
   MoqtControlParser parser(kWebTrans, visitor_);
   char subscribe[] = {
-      0x03, 0x01, 0x02, 0x01, 0x03,
-      0x66, 0x6f, 0x6f,              // track_namespace = "foo"
+      0x03, 0x1a, 0x01, 0x02, 0x01,
+      0x03, 0x66, 0x6f, 0x6f,        // track_namespace = "foo"
       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
       0x20, 0x02,                    // priority = 0x20 descending
       0x02,                          // filter_type = kLatestObject
@@ -701,8 +726,8 @@
 TEST_F(MoqtMessageSpecificTest, SubscribeDeliveryTimeoutTwice) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe[] = {
-      0x03, 0x01, 0x02, 0x01, 0x03,
-      0x66, 0x6f, 0x6f,              // track_namespace = "foo"
+      0x03, 0x18, 0x01, 0x02, 0x01,
+      0x03, 0x66, 0x6f, 0x6f,        // track_namespace = "foo"
       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
       0x20, 0x02,                    // priority = 0x20 descending
       0x02,                          // filter_type = kLatestObject
@@ -720,8 +745,8 @@
 TEST_F(MoqtMessageSpecificTest, SubscribeDeliveryTimeoutMalformed) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe[] = {
-      0x03, 0x01, 0x02, 0x01, 0x03,
-      0x66, 0x6f, 0x6f,              // track_namespace = "foo"
+      0x03, 0x14, 0x01, 0x02, 0x01,
+      0x03, 0x66, 0x6f, 0x6f,        // track_namespace = "foo"
       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
       0x20, 0x02,                    // priority = 0x20 descending
       0x02,                          // filter_type = kLatestObject
@@ -738,8 +763,8 @@
 TEST_F(MoqtMessageSpecificTest, SubscribeMaxCacheDurationTwice) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe[] = {
-      0x03, 0x01, 0x02, 0x01, 0x03,
-      0x66, 0x6f, 0x6f,              // track_namespace = "foo"
+      0x03, 0x18, 0x01, 0x02, 0x01,
+      0x03, 0x66, 0x6f, 0x6f,        // track_namespace = "foo"
       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
       0x20, 0x02,                    // priority = 0x20 descending
       0x02,                          // filter_type = kLatestObject
@@ -757,8 +782,8 @@
 TEST_F(MoqtMessageSpecificTest, SubscribeMaxCacheDurationMalformed) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe[] = {
-      0x03, 0x01, 0x02, 0x01, 0x03,
-      0x66, 0x6f, 0x6f,              // track_namespace = "foo"
+      0x03, 0x14, 0x01, 0x02, 0x01,
+      0x03, 0x66, 0x6f, 0x6f,        // track_namespace = "foo"
       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
       0x20, 0x02,                    // priority = 0x20 descending
       0x02,                          // filter_type = kLatestObject
@@ -775,7 +800,7 @@
 TEST_F(MoqtMessageSpecificTest, SubscribeOkHasAuthorizationInfo) {
   MoqtControlParser parser(kWebTrans, visitor_);
   char subscribe_ok[] = {
-      0x04, 0x01, 0x03,        // subscribe_id = 1, expires = 3
+      0x04, 0x10, 0x01, 0x03,  // subscribe_id = 1, expires = 3
       0x02, 0x01,              // group_order = 2, content exists
       0x0c, 0x14,              // largest_group_id = 12, largest_object_id = 20,
       0x02,                    // 2 parameters
@@ -792,10 +817,10 @@
 TEST_F(MoqtMessageSpecificTest, SubscribeUpdateHasAuthorizationInfo) {
   MoqtControlParser parser(kWebTrans, visitor_);
   char subscribe_update[] = {
-      0x02, 0x02, 0x03, 0x01, 0x05, 0x06,  // start and end sequences
-      0xaa,                                // priority = 0xaa
-      0x01,                                // 1 parameter
-      0x02, 0x03, 0x62, 0x61, 0x72,        // authorization_info = "bar"
+      0x02, 0x0c, 0x02, 0x03, 0x01, 0x05, 0x06,  // start and end sequences
+      0xaa,                                      // priority = 0xaa
+      0x01,                                      // 1 parameter
+      0x02, 0x03, 0x62, 0x61, 0x72,              // authorization_info = "bar"
   };
   parser.ProcessData(
       absl::string_view(subscribe_update, sizeof(subscribe_update)), false);
@@ -807,10 +832,10 @@
 TEST_F(MoqtMessageSpecificTest, AnnounceAuthorizationInfoTwice) {
   MoqtControlParser parser(kWebTrans, visitor_);
   char announce[] = {
-      0x06, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
-      0x02,                                // 2 params
-      0x02, 0x03, 0x62, 0x61, 0x72,        // authorization_info = "bar"
-      0x02, 0x03, 0x62, 0x61, 0x72,        // authorization_info = "bar"
+      0x06, 0x10, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
+      0x02,                                      // 2 params
+      0x02, 0x03, 0x62, 0x61, 0x72,              // authorization_info = "bar"
+      0x02, 0x03, 0x62, 0x61, 0x72,              // authorization_info = "bar"
   };
   parser.ProcessData(absl::string_view(announce, sizeof(announce)), false);
   EXPECT_EQ(visitor_.messages_received_, 0);
@@ -823,10 +848,10 @@
 TEST_F(MoqtMessageSpecificTest, AnnounceHasDeliveryTimeout) {
   MoqtControlParser parser(kWebTrans, visitor_);
   char announce[] = {
-      0x06, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
-      0x02,                                // 2 params
-      0x02, 0x03, 0x62, 0x61, 0x72,        // authorization_info = "bar"
-      0x03, 0x02, 0x67, 0x10,              // delivery_timeout = 10000
+      0x06, 0x0f, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
+      0x02,                                      // 2 params
+      0x02, 0x03, 0x62, 0x61, 0x72,              // authorization_info = "bar"
+      0x03, 0x02, 0x67, 0x10,                    // delivery_timeout = 10000
   };
   parser.ProcessData(absl::string_view(announce, sizeof(announce)), false);
   EXPECT_EQ(visitor_.messages_received_, 0);
@@ -888,6 +913,7 @@
   char big_message[2 * kMaxMessageHeaderSize];
   quic::QuicDataWriter writer(sizeof(big_message), big_message);
   writer.WriteVarInt62(static_cast<uint64_t>(MoqtMessageType::kServerSetup));
+  writer.WriteVarInt62(8 + kMaxMessageHeaderSize);
   writer.WriteVarInt62(0x1);                    // version
   writer.WriteVarInt62(0x1);                    // num_params
   writer.WriteVarInt62(0xbeef);                 // unknown param
@@ -904,9 +930,11 @@
 
 TEST_F(MoqtMessageSpecificTest, UnknownMessageType) {
   MoqtControlParser parser(kRawQuic, visitor_);
-  char message[4];
+  char message[6];
   quic::QuicDataWriter writer(sizeof(message), message);
   writer.WriteVarInt62(0xbeef);  // unknown message type
+  writer.WriteVarInt62(0x1);     // length
+  writer.WriteVarInt62(0x1);     // payload
   parser.ProcessData(absl::string_view(message, writer.length()), false);
   EXPECT_EQ(visitor_.messages_received_, 0);
   EXPECT_TRUE(visitor_.parsing_error_.has_value());
@@ -916,7 +944,7 @@
 TEST_F(MoqtMessageSpecificTest, LatestGroup) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe[] = {
-      0x03, 0x01, 0x02,              // id and alias
+      0x03, 0x15, 0x01, 0x02,        // id and alias
       0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
       0x20, 0x02,                    // priority = 0x20 descending
@@ -938,10 +966,10 @@
 TEST_F(MoqtMessageSpecificTest, LatestObject) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe[] = {
-      0x03, 0x01, 0x02,              // id and alias
+      0x03, 0x15, 0x01, 0x02,        // id and alias
       0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
-      0x20, 0x02,                    // priority = 0x20 descending
+      0x20, 0x02,                    // priority = 0x20, group order descending
       0x02,                          // filter_type = kLatestObject
       0x01,                          // 1 parameter
       0x02, 0x03, 0x62, 0x61, 0x72,  // authorization_info = "bar"
@@ -960,7 +988,7 @@
 TEST_F(MoqtMessageSpecificTest, InvalidDeliveryOrder) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe[] = {
-      0x03, 0x01, 0x02,              // id and alias
+      0x03, 0x15, 0x01, 0x02,        // id and alias
       0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
       0x20, 0x08,                    // priority = 0x20 ???
@@ -976,7 +1004,7 @@
 TEST_F(MoqtMessageSpecificTest, AbsoluteStart) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe[] = {
-      0x03, 0x01, 0x02,              // id and alias
+      0x03, 0x17, 0x01, 0x02,        // id and alias
       0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
       0x20, 0x02,                    // priority = 0x20 descending
@@ -1000,7 +1028,7 @@
 TEST_F(MoqtMessageSpecificTest, AbsoluteRangeExplicitEndObject) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe[] = {
-      0x03, 0x01, 0x02,              // id and alias
+      0x03, 0x19, 0x01, 0x02,        // id and alias
       0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
       0x20, 0x02,                    // priority = 0x20 descending
@@ -1026,7 +1054,7 @@
 TEST_F(MoqtMessageSpecificTest, AbsoluteRangeWholeEndGroup) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe[] = {
-      0x03, 0x01, 0x02,              // id and alias
+      0x03, 0x19, 0x01, 0x02,        // id and alias
       0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
       0x20, 0x02,                    // priority = 0x20 descending
@@ -1052,7 +1080,7 @@
 TEST_F(MoqtMessageSpecificTest, AbsoluteRangeEndGroupTooLow) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe[] = {
-      0x03, 0x01, 0x02,              // id and alias
+      0x03, 0x19, 0x01, 0x02,        // id and alias
       0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
       0x20, 0x02,                    // priority = 0x20 descending
@@ -1073,7 +1101,7 @@
 TEST_F(MoqtMessageSpecificTest, AbsoluteRangeExactlyOneObject) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe[] = {
-      0x03, 0x01, 0x02,              // id and alias
+      0x03, 0x14, 0x01, 0x02,        // id and alias
       0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
       0x20, 0x02,                    // priority = 0x20 descending
@@ -1091,9 +1119,9 @@
 TEST_F(MoqtMessageSpecificTest, SubscribeUpdateExactlyOneObject) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe_update[] = {
-      0x02, 0x02, 0x03, 0x01, 0x04, 0x07,  // start and end sequences
-      0x20,                                // priority
-      0x00,                                // No parameters
+      0x02, 0x07, 0x02, 0x03, 0x01, 0x04, 0x07,  // start and end sequences
+      0x20,                                      // priority
+      0x00,                                      // No parameters
   };
   parser.ProcessData(
       absl::string_view(subscribe_update, sizeof(subscribe_update)), false);
@@ -1103,10 +1131,10 @@
 TEST_F(MoqtMessageSpecificTest, SubscribeUpdateEndGroupTooLow) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe_update[] = {
-      0x02, 0x02, 0x03, 0x01, 0x03, 0x06,  // start and end sequences
-      0x20,                                // priority
-      0x01,                                // 1 parameter
-      0x02, 0x03, 0x62, 0x61, 0x72,        // authorization_info = "bar"
+      0x02, 0x0c, 0x02, 0x03, 0x01, 0x03, 0x06,  // start and end sequences
+      0x20,                                      // priority
+      0x01,                                      // 1 parameter
+      0x02, 0x03, 0x62, 0x61, 0x72,              // authorization_info = "bar"
   };
   parser.ProcessData(
       absl::string_view(subscribe_update, sizeof(subscribe_update)), false);
@@ -1118,7 +1146,7 @@
 TEST_F(MoqtMessageSpecificTest, AbsoluteRangeEndObjectTooLow) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe[] = {
-      0x03, 0x01, 0x02,              // id and alias
+      0x03, 0x19, 0x01, 0x02,        // id and alias
       0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
       0x20, 0x02,                    // priority = 0x20 descending
@@ -1139,8 +1167,8 @@
 TEST_F(MoqtMessageSpecificTest, SubscribeUpdateEndObjectTooLow) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe_update[] = {
-      0x02, 0x02, 0x03, 0x02, 0x04, 0x01,  // start and end sequences
-      0xf0, 0x00,                          // priority, no parameter
+      0x02, 0x07, 0x02, 0x03, 0x02, 0x04, 0x01,  // start and end sequences
+      0xf0, 0x00,                                // priority, no parameter
   };
   parser.ProcessData(
       absl::string_view(subscribe_update, sizeof(subscribe_update)), false);
@@ -1152,9 +1180,9 @@
 TEST_F(MoqtMessageSpecificTest, SubscribeUpdateNoEndGroup) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char subscribe_update[] = {
-      0x02, 0x02, 0x03, 0x02, 0x00, 0x01,  // start and end sequences
-      0x20,                                // priority
-      0x00,                                // No parameter
+      0x02, 0x07, 0x02, 0x03, 0x02, 0x00, 0x01,  // start and end sequences
+      0x20,                                      // priority
+      0x00,                                      // No parameter
   };
   parser.ProcessData(
       absl::string_view(subscribe_update, sizeof(subscribe_update)), false);
@@ -1167,7 +1195,7 @@
 TEST_F(MoqtMessageSpecificTest, ObjectAckNegativeDelta) {
   MoqtControlParser parser(kRawQuic, visitor_);
   char object_ack[] = {
-      0x71, 0x84,        // type
+      0x71, 0x84, 0x05,  // type
       0x01, 0x10, 0x20,  // subscribe ID, group, object
       0x40, 0x81,        // -0x40 time delta
   };
diff --git a/quiche/quic/moqt/test_tools/moqt_test_message.h b/quiche/quic/moqt/test_tools/moqt_test_message.h
index c694e8d..cc53381 100644
--- a/quiche/quic/moqt/test_tools/moqt_test_message.h
+++ b/quiche/quic/moqt/test_tools/moqt_test_message.h
@@ -63,6 +63,19 @@
   // message has a different layout of varints.
   virtual void ExpandVarints() = 0;
 
+  // This will cause a parsing error. Do not call this on Object Messages.
+  void DecreasePayloadLengthByOne() {
+    size_t length_offset =
+        0x1 << ((static_cast<uint8_t>(wire_image_[0]) & 0xc0) >> 6);
+    wire_image_[length_offset]--;
+  }
+  void IncreasePayloadLengthByOne() {
+    size_t length_offset =
+        0x1 << ((static_cast<uint8_t>(wire_image_[0]) & 0xc0) >> 6);
+    wire_image_[length_offset]++;
+    set_wire_image_size(wire_image_size_ + 1);
+  }
+
  protected:
   void SetWireImage(uint8_t* wire_image, size_t wire_image_size) {
     memcpy(wire_image_, wire_image, wire_image_size);
@@ -74,13 +87,47 @@
   // Each character in |varints| corresponds to a byte in the original message.
   // If there is a 'v', it is a varint that should be expanded. If '-', skip
   // to the next byte.
-  void ExpandVarintsImpl(absl::string_view varints) {
+  // Always expand the message length field (if a control message) to 2 bytes,
+  // so it's a known length that is large enough to be safe. The second byte
+  // of |varints| does not matter.
+  void ExpandVarintsImpl(absl::string_view varints,
+                         bool is_control_message = true) {
     int next_varint_len = 2;
     char new_wire_image[kMaxMessageHeaderSize + 1];
     quic::QuicDataReader reader(
         absl::string_view(wire_image_, wire_image_size_));
     quic::QuicDataWriter writer(sizeof(new_wire_image), new_wire_image);
     size_t i = 0;
+    size_t length_field = 0;
+    if (is_control_message) {
+      // the length will be a 16-bit varint.
+      bool nonvarint_type = false;
+      while (varints[i] == '-') {
+        ++i;
+        nonvarint_type = true;
+        uint8_t byte;
+        reader.ReadUInt8(&byte);
+        writer.WriteUInt8(byte);
+      }
+      uint64_t value;
+      if (!nonvarint_type) {
+        ++i;
+        reader.ReadVarInt62(&value);
+        writer.WriteVarInt62WithForcedLength(
+            value, static_cast<quiche::QuicheVariableLengthIntegerLength>(
+                       next_varint_len));
+        next_varint_len *= 2;
+        if (next_varint_len == 16) {
+          next_varint_len = 2;
+        }
+      }
+      reader.ReadVarInt62(&value);
+      ++i;
+      length_field = writer.length();
+      // Write in current length as a 2B placeholder.
+      writer.WriteVarInt62WithForcedLength(
+          value, static_cast<quiche::QuicheVariableLengthIntegerLength>(2));
+    }
     while (!reader.IsDoneReading()) {
       if (i >= varints.length() || varints[i++] == '-') {
         uint8_t byte;
@@ -100,6 +147,10 @@
     }
     memcpy(wire_image_, new_wire_image, writer.length());
     wire_image_size_ = writer.length();
+    if (is_control_message) {
+      wire_image_[length_field + 1] =
+          static_cast<uint8_t>(writer.length() - length_field - 2);
+    }
   }
 
  private:
@@ -176,7 +227,7 @@
     object_.forwarding_preference = MoqtForwardingPreference::kDatagram;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvvvv-v---"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvvv-v---", false); }
 
  private:
   uint8_t raw_packet_[10] = {
@@ -196,7 +247,7 @@
     object_.payload_length = 3;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvv-vvv"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvv-vvv", false); }
 
  private:
   // Some tests check that a FIN sent at the halfway point of a message results
@@ -222,7 +273,7 @@
     object_.object_id = 10;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvv"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvv", false); }
 
  private:
   uint8_t raw_packet_[6] = {
@@ -239,7 +290,7 @@
     object_.subgroup_id = 8;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvvvv-vv"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvvv-vv", false); }
 
   bool SetPayloadLength(uint8_t payload_length) {
     if (payload_length > 63) {
@@ -271,7 +322,7 @@
     object_.object_id = 9;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vv"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vv", false); }
 
  private:
   uint8_t raw_packet_[5] = {
@@ -285,7 +336,8 @@
     if (webtrans) {
       // Should not send PATH.
       client_setup_.path = std::nullopt;
-      raw_packet_[5] = 0x02;  // only two parameters
+      raw_packet_[2] = 0x0a;  // adjust payload length (-5)
+      raw_packet_[6] = 0x02;  // only two parameters
       SetWireImage(raw_packet_, sizeof(raw_packet_) - 5);
     } else {
       SetWireImage(raw_packet_, sizeof(raw_packet_));
@@ -323,11 +375,11 @@
 
   void ExpandVarints() override {
     if (client_setup_.path.has_value()) {
-      ExpandVarintsImpl("--vvvvvv-vv-vv---");
+      ExpandVarintsImpl("--vvvvvvv-vv-vv---");
       // first two bytes are already a 2B varint. Also, don't expand parameter
       // varints because that messes up the parameter length field.
     } else {
-      ExpandVarintsImpl("--vvvvvv-vv-");
+      ExpandVarintsImpl("--vvvvvvv-vv-");
     }
   }
 
@@ -336,8 +388,8 @@
   }
 
  private:
-  uint8_t raw_packet_[17] = {
-      0x40, 0x40,                    // type
+  uint8_t raw_packet_[18] = {
+      0x40, 0x40, 0x0f,              // type
       0x02, 0x01, 0x02,              // versions
       0x03,                          // 3 parameters
       0x00, 0x01, 0x03,              // role = PubSub
@@ -377,7 +429,8 @@
   }
 
   void ExpandVarints() override {
-    ExpandVarintsImpl("--vvvv-vv-");  // first two bytes are already a 2b varint
+    ExpandVarintsImpl("--vvvvv-vv-");  // first two bytes are already a 2b
+                                       // varint
   }
 
   MessageStructuredData structured_data() const override {
@@ -385,8 +438,8 @@
   }
 
  private:
-  uint8_t raw_packet_[10] = {
-      0x40, 0x41,        // type
+  uint8_t raw_packet_[11] = {
+      0x40, 0x41, 0x08,  // type
       0x01, 0x02,        // version, two parameters
       0x00, 0x01, 0x03,  // role = PubSub
       0x02, 0x01, 0x32,  // max_subscribe_id = 50
@@ -450,7 +503,7 @@
   }
 
   void ExpandVarints() override {
-    ExpandVarintsImpl("vvvvv---v------vvvvvv---vv--vv--");
+    ExpandVarintsImpl("vvvvvv---v------vvvvvv---vv--vv--");
   }
 
   MessageStructuredData structured_data() const override {
@@ -458,8 +511,8 @@
   }
 
  private:
-  uint8_t raw_packet_[32] = {
-      0x03, 0x01, 0x02,              // id and alias
+  uint8_t raw_packet_[33] = {
+      0x03, 0x1f, 0x01, 0x02,        // id and alias
       0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
       0x20,                          // subscriber priority = 0x20
@@ -522,25 +575,25 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvv--vvvvv--vv--"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvv--vvvvv--vv--"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(subscribe_ok_);
   }
 
   void SetInvalidContentExists() {
-    raw_packet_[4] = 0x02;
+    raw_packet_[5] = 0x02;
     SetWireImage(raw_packet_, sizeof(raw_packet_));
   }
 
   void SetInvalidDeliveryOrder() {
-    raw_packet_[3] = 0x10;
+    raw_packet_[4] = 0x10;
     SetWireImage(raw_packet_, sizeof(raw_packet_));
   }
 
  private:
-  uint8_t raw_packet_[16] = {
-      0x04, 0x01, 0x03,        // subscribe_id = 1, expires = 3
+  uint8_t raw_packet_[17] = {
+      0x04, 0x0f, 0x01, 0x03,  // subscribe_id = 1, expires = 3
       0x02, 0x01,              // group_order = 2, content exists
       0x0c, 0x14,              // largest_group_id = 12, largest_object_id = 20,
       0x02,                    // 2 parameters
@@ -587,15 +640,16 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvvv---v"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvvv---v"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(subscribe_error_);
   }
 
  private:
-  uint8_t raw_packet_[8] = {
-      0x05, 0x02,              // subscribe_id = 2
+  uint8_t raw_packet_[9] = {
+      0x05, 0x07,
+      0x02,                    // subscribe_id = 2
       0x01,                    // error_code = 2
       0x03, 0x62, 0x61, 0x72,  // reason_phrase = "bar"
       0x04,                    // track_alias = 4
@@ -624,15 +678,15 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vv"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvv"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(unsubscribe_);
   }
 
  private:
-  uint8_t raw_packet_[2] = {
-      0x0a, 0x03,  // subscribe_id = 3
+  uint8_t raw_packet_[3] = {
+      0x0a, 0x01, 0x03,  // subscribe_id = 3
   };
 
   MoqtUnsubscribe unsubscribe_ = {
@@ -667,22 +721,22 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvvv---vv"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvvv---vv"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(subscribe_done_);
   }
 
   void SetInvalidContentExists() {
-    raw_packet_[6] = 0x02;
+    raw_packet_[7] = 0x02;
     SetWireImage(raw_packet_, sizeof(raw_packet_));
   }
 
  private:
-  uint8_t raw_packet_[9] = {
-      0x0b, 0x02, 0x03,  // subscribe_id = 2, error_code = 3,
-      0x02, 0x68, 0x69,  // reason_phrase = "hi"
-      0x01, 0x08, 0x0c,  // final_id = (8,12)
+  uint8_t raw_packet_[10] = {
+      0x0b, 0x08, 0x02, 0x03,  // subscribe_id = 2, error_code = 3,
+      0x02, 0x68, 0x69,        // reason_phrase = "hi"
+      0x01, 0x08, 0x0c,        // final_id = (8,12)
   };
 
   MoqtSubscribeDone subscribe_done_ = {
@@ -732,19 +786,19 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvvvvv-vvv---"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvvvvv-vvv---"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(subscribe_update_);
   }
 
  private:
-  uint8_t raw_packet_[16] = {
-      0x02, 0x02, 0x03, 0x01, 0x05, 0x06,  // start and end sequences
-      0xaa,                                // subscriber_priority
-      0x02,                                // 1 parameter
-      0x03, 0x02, 0x67, 0x10,              // delivery_timeout = 10000
-      0x04, 0x02, 0x67, 0x10,              // max_cache_duration = 10000
+  uint8_t raw_packet_[17] = {
+      0x02, 0x0f, 0x02, 0x03, 0x01, 0x05, 0x06,  // start and end sequences
+      0xaa,                                      // subscriber_priority
+      0x02,                                      // 1 parameter
+      0x03, 0x02, 0x67, 0x10,                    // delivery_timeout = 10000
+      0x04, 0x02, 0x67, 0x10,                    // max_cache_duration = 10000
   };
 
   MoqtSubscribeUpdate subscribe_update_ = {
@@ -780,18 +834,18 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvv---vvv---vv--"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvv---vvv---vv--"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(announce_);
   }
 
  private:
-  uint8_t raw_packet_[16] = {
-      0x06, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
-      0x02,                                // 2 parameters
-      0x02, 0x03, 0x62, 0x61, 0x72,        // authorization_info = "bar"
-      0x04, 0x02, 0x67, 0x10,              // max_cache_duration = 10000ms
+  uint8_t raw_packet_[17] = {
+      0x06, 0x0f, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
+      0x02,                                      // 2 parameters
+      0x02, 0x03, 0x62, 0x61, 0x72,              // authorization_info = "bar"
+      0x04, 0x02, 0x67, 0x10,                    // max_cache_duration = 10000ms
   };
 
   MoqtAnnounce announce_ = {
@@ -818,15 +872,15 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvv---"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvv---"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(announce_ok_);
   }
 
  private:
-  uint8_t raw_packet_[6] = {
-      0x07, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
+  uint8_t raw_packet_[7] = {
+      0x07, 0x05, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
   };
 
   MoqtAnnounceOk announce_ok_ = {
@@ -857,17 +911,17 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvv---vv---"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvv---vv---"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(announce_error_);
   }
 
  private:
-  uint8_t raw_packet_[11] = {
-      0x08, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
-      0x01,                                // error_code = 1
-      0x03, 0x62, 0x61, 0x72,              // reason_phrase = "bar"
+  uint8_t raw_packet_[12] = {
+      0x08, 0x0a, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
+      0x01,                                      // error_code = 1
+      0x03, 0x62, 0x61, 0x72,                    // reason_phrase = "bar"
   };
 
   MoqtAnnounceError announce_error_ = {
@@ -900,17 +954,17 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvv---vv---"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvv---vv---"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(announce_cancel_);
   }
 
  private:
-  uint8_t raw_packet_[11] = {
-      0x0c, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
-      0x01,                                // error_code = 1
-      0x03, 0x62, 0x61, 0x72,              // reason_phrase = "bar"
+  uint8_t raw_packet_[12] = {
+      0x0c, 0x0a, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
+      0x01,                                      // error_code = 1
+      0x03, 0x62, 0x61, 0x72,                    // reason_phrase = "bar"
   };
 
   MoqtAnnounceCancel announce_cancel_ = {
@@ -935,16 +989,16 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvv---v----"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvv---v----"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(track_status_request_);
   }
 
  private:
-  uint8_t raw_packet_[11] = {
-      0x0d, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
-      0x04, 0x61, 0x62, 0x63, 0x64,        // track_name = "abcd"
+  uint8_t raw_packet_[12] = {
+      0x0d, 0x0a, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
+      0x04, 0x61, 0x62, 0x63, 0x64,              // track_name = "abcd"
   };
 
   MoqtTrackStatusRequest track_status_request_ = {
@@ -967,15 +1021,15 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvv---"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvv---"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(unannounce_);
   }
 
  private:
-  uint8_t raw_packet_[6] = {
-      0x09, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace
+  uint8_t raw_packet_[7] = {
+      0x09, 0x05, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace
   };
 
   MoqtUnannounce unannounce_ = {
@@ -1010,17 +1064,17 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvv---v----vvv"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvv---v----vvv"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(track_status_);
   }
 
  private:
-  uint8_t raw_packet_[14] = {
-      0x0e, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
-      0x04, 0x61, 0x62, 0x63, 0x64,        // track_name = "abcd"
-      0x00, 0x0c, 0x14,                    // status, last_group, last_object
+  uint8_t raw_packet_[15] = {
+      0x0e, 0x0d, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
+      0x04, 0x61, 0x62, 0x63, 0x64,              // track_name = "abcd"
+      0x00, 0x0c, 0x14,  // status, last_group, last_object
   };
 
   MoqtTrackStatus track_status_ = {
@@ -1046,15 +1100,15 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vv---"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvv---"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(goaway_);
   }
 
  private:
-  uint8_t raw_packet_[5] = {
-      0x10, 0x03, 0x66, 0x6f, 0x6f,
+  uint8_t raw_packet_[6] = {
+      0x10, 0x04, 0x03, 0x66, 0x6f, 0x6f,
   };
 
   MoqtGoAway goaway_ = {
@@ -1081,17 +1135,17 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvv---vvv---"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvv---vvv---"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(subscribe_namespace_);
   }
 
  private:
-  uint8_t raw_packet_[12] = {
-      0x11, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // namespace = "foo"
-      0x01,                                // 1 parameter
-      0x02, 0x03, 0x62, 0x61, 0x72,        // authorization_info = "bar"
+  uint8_t raw_packet_[13] = {
+      0x11, 0x0b, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // namespace = "foo"
+      0x01,                                      // 1 parameter
+      0x02, 0x03, 0x62, 0x61, 0x72,              // authorization_info = "bar"
   };
 
   MoqtSubscribeNamespace subscribe_namespace_ = {
@@ -1116,15 +1170,15 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvv---"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvv---"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(subscribe_namespace_ok_);
   }
 
  private:
-  uint8_t raw_packet_[6] = {
-      0x12, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // namespace = "foo"
+  uint8_t raw_packet_[7] = {
+      0x12, 0x05, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // namespace = "foo"
   };
 
   MoqtSubscribeNamespaceOk subscribe_namespace_ok_ = {
@@ -1155,17 +1209,17 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvv---vv---"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvv---vv---"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(subscribe_namespace_error_);
   }
 
  private:
-  uint8_t raw_packet_[11] = {
-      0x13, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
-      0x01,                                // error_code = 1
-      0x03, 0x62, 0x61, 0x72,              // reason_phrase = "bar"
+  uint8_t raw_packet_[12] = {
+      0x13, 0x0a, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
+      0x01,                                      // error_code = 1
+      0x03, 0x62, 0x61, 0x72,                    // reason_phrase = "bar"
   };
 
   MoqtSubscribeNamespaceError subscribe_namespace_error_ = {
@@ -1190,15 +1244,15 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvv---"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvv---"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(unsubscribe_namespace_);
   }
 
  private:
-  uint8_t raw_packet_[6] = {
-      0x14, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace
+  uint8_t raw_packet_[7] = {
+      0x14, 0x05, 0x01, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace
   };
 
   MoqtUnsubscribeNamespace unsubscribe_namespace_ = {
@@ -1221,15 +1275,16 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vv"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvv"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(max_subscribe_id_);
   }
 
  private:
-  uint8_t raw_packet_[2] = {
+  uint8_t raw_packet_[3] = {
       0x15,
+      0x01,
       0x0b,
   };
 
@@ -1265,15 +1320,15 @@
     return true;
   }
 
-  void ExpandVarints() override { ExpandVarintsImpl("vvvvv"); }
+  void ExpandVarints() override { ExpandVarintsImpl("vvvvvv"); }
 
   MessageStructuredData structured_data() const override {
     return TestMessageBase::MessageStructuredData(object_ack_);
   }
 
  private:
-  uint8_t raw_packet_[6] = {
-      0x71, 0x84,        // type
+  uint8_t raw_packet_[7] = {
+      0x71, 0x84, 0x04,  // type
       0x01, 0x10, 0x20,  // subscribe ID, group, object
       0x20,              // 0x10 time delta
   };