| Internet-Draft | moq-sub-flow-control | October 2026 |
| Frindell & Swett | Expires 10 April 2027 | [Page] |
This document defines an extension to Media over QUIC Transport (MOQT) that lets a subscriber limit the number of subgroup streams and the total bytes a publisher may send for an individual subscription. It defines a Setup Option to negotiate the extension and set initial limits, message parameters for advertising these limits, messages for granting credit and signaling flow control state, and a session error code.¶
This note is to be removed before publishing as an RFC.¶
The latest revision of this draft can be found at https://afrind.github.io/draft-frindell-moq-subscription-flow-control/draft-frindell-moq-subscription-flow-control.html. Status information for this document may be found at https://datatracker.ietf.org/doc/draft-frindell-moq-subscription-flow-control/.¶
Discussion of this document takes place on the Media Over QUIC Working Group mailing list (mailto:moq@ietf.org), which is archived at https://mailarchive.ietf.org/arch/browse/moq/. Subscribe at https://www.ietf.org/mailman/listinfo/moq/.¶
Source for this draft and an issue tracker can be found at https://github.com/afrind/draft-frindell-moq-subscription-flow-control.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 10 April 2027.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
Media over QUIC Transport (MOQT) [MOQT] delivers a subscription's Objects across one or more subgroup streams, but provides no way for a subscriber to bound how many streams or bytes a publisher sends for that subscription. Transport-layer flow control operates per stream and per session, so it cannot express a limit spanning a subscription's streams.¶
This extension lets a subscriber limit the total subgroup streams (MAX_SUB_STREAMS) and total bytes (MAX_SUB_BYTES) for a subscription, and grant further credit with SUB_FLOW_CONTROL_UPDATE. Publishers signal that they are blocked with SUB_STREAMS_BLOCKED and SUB_BYTES_BLOCKED, and report the final size of reset subgroup streams with SUBGROUP_RESET. Violations terminate the session with FLOW_CONTROL_EXCEEDED.¶
Support for this extension is negotiated during session establishment using the SUBSCRIPTION_FLOW_CONTROL Setup Option (Section 3).¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
This document uses the terminology and wire format notation of [MOQT]. The subscriber sets the limits and the publisher honors them, regardless of which endpoint is the client or server.¶
An endpoint indicates support for this extension by including the SUBSCRIPTION_FLOW_CONTROL Setup Option in its SETUP message. The option also sets the initial limits for subscriptions in which the endpoint is the subscriber (Section 4).¶
SUBSCRIPTION_FLOW_CONTROL Setup Option {
Option Type (vi64) = 0x0B,
Length (vi64),
Initial Max Sub Streams (vi64),
Initial Max Sub Bytes (vi64),
}
Initial Max Sub Streams: The initial MAX_SUB_STREAMS limit.¶
Initial Max Sub Bytes: The initial MAX_SUB_BYTES limit.¶
When an endpoint receives a SUBSCRIPTION_FLOW_CONTROL Setup Option whose value
does not contain exactly two varints, it MUST close the session with a
KEY_VALUE_FORMATTING_ERROR.¶
The extension is negotiated when an endpoint has both sent and received this option, per the extension negotiation described in [MOQT]. It applies to both directions of the session.¶
An endpoint that offers this extension MUST support RESET_STREAM_AT
([RELIABLE-RESET]). When an endpoint negotiates this extension with a peer
that does not support RESET_STREAM_AT, it MUST close the session with a
PROTOCOL_VIOLATION.¶
Every subscription has a stream limit and a byte limit, initialized from the subscriber's SUBSCRIPTION_FLOW_CONTROL Setup Option (Section 3.1), which SUBSCRIBE or SUBSCRIBE_TRACKS can override (Section 5). The subscriber grants additional credit with SUB_FLOW_CONTROL_UPDATE (Section 6.1). Credit is not granted with REQUEST_UPDATE because it solicits a response, which is unnecessary.¶
The limits apply only to subgroup streams; Objects sent as datagrams are not counted. Limits and the messages defined here are scoped to a single session and are not forwarded. A relay honors its downstream subscriber's limits and independently sets its own limits toward its upstream publisher.¶
Limits are per subscription and cumulative over its lifetime: the stream count
is the total number of subgroup streams opened, and the byte count is the total
bytes sent across them (Section 4.3). A publisher MUST NOT exceed a
limit in effect for a subscription. When a subscriber detects a violation, it
MUST close the session with a FLOW_CONTROL_EXCEEDED (Section 7).¶
The subscriber attributes each subgroup stream to a subscription by its Track
Alias, so when the extension is negotiated, a publisher MUST NOT assign the same
Track Alias to more than one subscription in the session, even if the
subscriptions are to the same Track or are not concurrent. When a subscriber
detects a SUBSCRIBE_OK or PUBLISH with a Track Alias previously assigned to
another subscription, it MUST close the session with a DUPLICATE_TRACK_ALIAS.¶
When the extension is negotiated, every SUBGROUP_HEADER includes a Stream Sequence field:¶
SUBGROUP_HEADER {
Type Flags (vi64),
Track Alias (vi64),
Group ID (vi64),
[Subgroup ID (vi64),]
[Publisher Priority (8),]
Stream Sequence (vi64),
}
Stream Sequence uniquely identifies a subgroup stream within its subscription. The publisher sets it to 0 on the first subgroup stream it opens for a subscription and increments it by 1 for each subsequent stream.¶
When a subscriber receives a SUBGROUP_HEADER with a Stream Sequence greater than
or equal to the stream limit, it MUST close the session with a
FLOW_CONTROL_EXCEEDED. When a subscriber detects a Stream Sequence it has
already received for the subscription, it MUST close the session with a
PROTOCOL_VIOLATION.¶
When sending would exceed a limit, the publisher MUST NOT open a subgroup stream beyond the stream limit and MUST NOT send bytes beyond the byte limit, even if this means stopping in the middle of a stream. It retains the blocked Objects until it receives additional credit, and SHOULD send SUB_STREAMS_BLOCKED or SUB_BYTES_BLOCKED, as applicable.¶
Being blocked does not extend an Object's lifetime; the delivery timeouts of [MOQT] (SUBGROUP_DELIVERY_TIMEOUT and OBJECT_DELIVERY_TIMEOUT) continue to apply. A subgroup stream reset because of an expired timeout is accounted for as described in Section 4.3.¶
If retaining blocked Objects would exceed its resource limits, a publisher MAY
terminate the subscription with PUBLISH_DONE and TOO_FAR_BEHIND ([MOQT]).¶
The byte count includes all bytes serialized on the subscription's subgroup streams: the SUBGROUP_HEADER (including the stream type) and each Object's header fields and payload. It excludes QUIC and WebTransport framing.¶
Accounting is at byte granularity. A publisher MAY send part of an Object and stop at the byte limit, leaving the stream open and resuming when credit arrives, subject to the delivery timeout and ordering rules of [MOQT].¶
Each subgroup stream consumes byte credit exactly once. For a stream closed with a FIN, the bytes received consume credit.¶
When a publisher resets a stream, it reports the bytes sent on it in the Final Size field of SUBGROUP_RESET (Section 6.2), and the stream consumes that much credit.¶
A publisher MUST reset subgroup streams using RESET_STREAM_AT with a reliable_size that includes the SUBGROUP_HEADER, so the subscriber always learns the stream's Stream Sequence (Section 4.1) and can match it to the corresponding SUBGROUP_RESET.¶
On native QUIC, this Final Size equals that of RESET_STREAM_AT
([RELIABLE-RESET]). WebTransport ([WebTransport]) implementations do not
necessarily expose the transport Final Size. When a subscriber receives a
SUBGROUP_RESET whose Final Size does not match the one reported by the
transport, it MUST close the session with a PROTOCOL_VIOLATION.¶
For example, with 100 bytes of credit and a 200-byte Object:¶
1. Publisher sends 100 bytes (SUBGROUP_HEADER, Object header, partial payload), reaching the limit, and SHOULD send SUB_BYTES_BLOCKED. 2. The Object's delivery timeout expires. 3. Publisher resets the stream and sends SUBGROUP_RESET with Final Size = 100. 4. The stream consumes 100 bytes of credit: limit reached, not exceeded.¶
This extension defines two Message Parameters ([MOQT]). If set in SUBSCRIBE or SUBSCRIBE_TRACKS, each parameter overrides the initial limit (Section 3.1), even if the value is smaller. In PUBLISH, it echoes the value from the corresponding SUBSCRIBE_TRACKS. When sent in SUB_FLOW_CONTROL_UPDATE, the value is added to the current limit.¶
A SUB_FLOW_CONTROL_UPDATE MUST NOT raise a limit above 2^64-1. When a publisher
receives a SUB_FLOW_CONTROL_UPDATE that would raise a limit above 2^64-1, it
MUST close the session with a PROTOCOL_VIOLATION.¶
MAX_SUB_STREAMS (Parameter Type 0x33) is a varint limiting the total number of subgroup streams the publisher can open for the subscription.¶
MAX_SUB_BYTES (Parameter Type 0x36) is a varint limiting the total bytes the publisher can send across the subscription's subgroup streams (Section 4.3).¶
Each message below is sent on the subscription's request stream using MOQT control message framing with a 16-bit Length ([MOQT]). None consumes a Request ID or solicits a response.¶
A subscriber sends SUB_FLOW_CONTROL_UPDATE to grant additional credit. It MAY
be sent any time after the subscription is established, whether or not the
publisher is blocked, so a subscriber that intends to grant credit MUST keep the
send direction of the request stream open. It has no effect if received after
the subscription ends.¶
Each parameter value is a delta to the current limit, so limits never decrease.
When a publisher receives a SUB_FLOW_CONTROL_UPDATE with a delta of 0, it MUST
close the session with a PROTOCOL_VIOLATION.¶
SUB_FLOW_CONTROL_UPDATE Message {
Type (vi64) = 0x14,
Length (16),
Number of Parameters (vi64),
Parameters (..) ...,
}
Parameters: MAX_SUB_STREAMS and/or MAX_SUB_BYTES, each granting additional
credit. When a publisher receives a SUB_FLOW_CONTROL_UPDATE with neither
parameter, it MUST close the session with a PROTOCOL_VIOLATION.¶
A publisher sends SUBGROUP_RESET to report the final byte count of a reset
subgroup stream (Section 4.3).¶
SUBGROUP_RESET Message {
Type (vi64) = 0x1F,
Length (16),
Stream Sequence (vi64),
Final Size (vi64),
}
Stream Sequence: The Stream Sequence of the reset subgroup stream (Section 4.1).¶
Final Size: The bytes sent on the stream before it was reset.¶
A publisher sends SUB_STREAMS_BLOCKED when it wants to open a subgroup stream
but MAX_SUB_STREAMS prevents it.¶
SUB_STREAMS_BLOCKED Message {
Type (vi64) = 0x12,
Length (16),
Maximum Streams (vi64),
}
Maximum Streams: The stream limit that was reached.¶
A publisher sends SUB_BYTES_BLOCKED when it has data to send but MAX_SUB_BYTES
prevents it.¶
SUB_BYTES_BLOCKED Message {
Type (vi64) = 0x13,
Length (16),
Maximum Bytes (vi64),
}
Maximum Bytes: The byte limit that was reached.¶
A session termination error code indicating that the peer violated a subscription flow control limit (MAX_SUB_STREAMS or MAX_SUB_BYTES).¶
These limits let a subscriber bound the resources a publisher consumes per subscription, complementing transport flow control. A subscriber SHOULD set limits consistent with the resources it will devote to a subscription.¶
SUB_STREAMS_BLOCKED and SUB_BYTES_BLOCKED are advisory. A subscriber MUST NOT rely on receiving them and MUST enforce limits regardless. A subscriber that grants credit only in response to them could stall a publisher that does not send them; granting credit proactively avoids this.¶
A misbehaving publisher could under-report Final Size in SUBGROUP_RESET to evade MAX_SUB_BYTES; Section 4.3 describes how a subscriber detects this when the transport reports the stream's Final Size.¶
This document registers entries in registries established by [MOQT]. All codepoints are provisional pending working group adoption and can be reassigned by IANA to avoid collisions.¶
IANA is requested to add the following entry to the "MOQT Setup Options" registry:¶
| Type | Name | Specification |
|---|---|---|
| 0x0B | SUBSCRIPTION_FLOW_CONTROL | Section 3.1 |
IANA is requested to add the following entries to the "MOQT Message Parameters" registry:¶
| Parameter Type | Parameter Name | Specification |
|---|---|---|
| 0x33 | MAX_SUB_STREAMS | Section 5.1 |
| 0x36 | MAX_SUB_BYTES | Section 5.2 |
IANA is requested to add the following entries to the "MOQT Message Types" registry. None is the first message on a stream.¶
| ID | Messages | Stream |
|---|---|---|
| 0x12 | SUB_STREAMS_BLOCKED (Section 6.3) | Request |
| 0x13 | SUB_BYTES_BLOCKED (Section 6.4) | Request |
| 0x14 | SUB_FLOW_CONTROL_UPDATE (Section 6.1) | Request |
| 0x1F | SUBGROUP_RESET (Section 6.2) | Request |
IANA is requested to add the following entry to the "MOQT Session Termination Error Codes" registry:¶
| Name | Code | Specification |
|---|---|---|
| FLOW_CONTROL_EXCEEDED | 0x1C | Section 7 |
This extension is derived from a proposal to add subscription flow control to the base Media over QUIC Transport protocol. The initial conversion of that proposal into this extension draft was drafted with the assistance of Claude Code.¶