Change:
4.3. <ins> A WebTransport endpoint may send a RESET_STREAM or a STOP_SENDING frame for a WebTransport data stream.  Those signals are propagated by the WebTransport implementation to the application. A WebTransport application SHALL provide an error code for those operations.  Since WebTransport shares the error code space with HTTP/3, WebTransport application errors for streams are limited to an unsigned 8-bit integer, assuming values between 0x00 and 0xff. WebTransport implementations SHALL remap those error codes into an error range where 0x00 corresponds to 0x52e4a40fa8db, and 0xff corresponds to 0x52e4a40fa9e2.  Note that there are code points inside that range of form "0x1f * N + 0x21" that are reserved by Section 8.1 of HTTP3; those have to be accounted for when mapping the error codes by skipping them (i.e. the two HTTP/3 error codepoints adjacent to a GREASE codepoint would map to two adjacent WebTransport application error codepoints).  An example pseudocode can be seen in fig-remap-errors. WebTransport data streams are associated with sessions through a header at the beginning of the stream; resetting a stream may result in that data being discarded.  Because of that, WebTransport application error codes are best effort, as the WebTransport stack is not always capable of associating the reset code with a session.  The only exception is the situation where there is only one session on a given HTTP/3 connection, and no intermediaries between the client and the server. WebTransport implementations SHALL forward the error code for a stream associated with a known session to the application that owns that session; similarly, the intermediaries SHALL reset the streams with corresponding error code when receiving a reset from the peer. If a WebTransport implementation intentionally allows only one session over a given HTTP/3 connection, it SHALL forward the error codes within WebTransport application error code range to the application that owns the only session on that connection. 4.4. </ins> Datagrams can be sent using the DATAGRAM frame as defined in QUIC- DATAGRAM and HTTP3-DATAGRAM.  For all HTTP/3 connections in which the SETTINGS_ENABLE_WEBTRANSPORT option is negotiated, the Flow

Discussion:
cc NAME
If we are going to let the API users supply their own stream reset code, we should figure out how this is represented on the wire. We could potentially use the error codes as-is and say they mean different things for WebTransport streams than what they mean for normal streams, but I am not sure this is sound as we don't always know that a stream is a WebTransport stream at the time we process the reset (also this sounds like a pain to implement). One possibility would be to reserve a block within HTTP/3 error code space. However, since HTTP/3 error codes contain GREASE code-points throughout, we might end up having to "de-grease" and "re-grease" them as the largest continuous block only has 255 codepoints available. Alternatively, if we decide to just send RESET_STREAM as a part of CONNECT stream due to issues in , we could just send the error code there, and keep one single code for user-initiated termination. Whatever we decide here should probably work for H/2 as well. cc NAME
Are application developers asking for custom reset error codes? Making reset unreliable and non-customizable would be much easier if that's sufficient for everyone's needs.
Reset error codes are special in the sense that they are reliably delivered by the transport (unlike the data, which all can be lost to a reset). So I imagine an application would want to be able to tell apart a regular reset (e.g. due to stream TTL expiring), vs reset due to an error. NAME might have opinions on this, since he filed .
We went through a concerted effort to reduce the number of H3 error codes. Partly because knowing when to use the right code (from an implementation persepctive) can be hard. H2's space is small, I don't know if the experts would allow one application to reserve a large block. At a minimum we probably need a WEBTRANSNOERROR. Maybe there are some error codes for "Web transport wire protocol error". Anticipating more specific error codes for apps using webtransport is hard. Some motivating use cases might help.
It's 32-bit, so I think we could probably get 16 bits worth of error codes.
Ah quire right, I was getting mixed up with frame type which is 8 bits.

But still, reserving half the code points for one usage of H2 seems overboard. Given that H2 suffices with about a dozen error codes I really wonder what WebTransport thinks it can achieve by using so many. Maybe the ask is for a "retire stream with a status"? In which case an alternate design would be to add a control frame for webstransport that contains your own space or possibly a reason phrasr and then a generic error code such as WEBTRANSSTREAMABORT to disambiguate it from other H3 errors.
I think it's 1/65536th of the error space, not 1/2. WebTransport by itself does not need that many error codes (I have so far three or four in the code that I will write a PR as soon as I'm done); the question here is what do applications running on top of it want.
The exposes connection error codes, so it's something the transport would need to support. I think removing them would be a W3C conversation. Actually for my application, we wanted to signal when the connection was terminated gracefully versus an unexpected error. We tried using CONNECTION_CLOSE with application error codes but the QuicTransport implementation in Chrome always raised "Connection Lost" regardless of the code. We had to resort to making a new stream and our own, high priority message when the connection was closed. This also meant waiting for the message to be acknowledged before actually closing the connection, otherwise the message would be lost. So yeah, I think immediately closing a connection with an error code is useful functionality, hence why it's in QUIC as well.
Would it work to just defer that the registration to applications over WebTransport? I appreciate it's nice to have a contiguous block but there's hardly much churn in that registry and I don't know what practical benefit a contiguous range adds for distinct uses of WebTransport. I'm confused if you're attempting to reserve a block that is then allocated via some sub-protocol negotiation, or if you intend to run a registration scheme inside your reserved block. Or something else.
Are you suggesting that we should let WebTransport applications send arbitrary HTTP/3 error codes? That could work, but I am not sure what are the security consequences of that. If we only reserve a block, the error codes outside of that block are "privileged", i.e.

only the browser (but not the untrusted web application) can send them.
That's a good point and puts more weight behind reserving a block that can only be used by the WebTransport API.
NAME could you elaborate on how your application reacts differently to graceful termination of a stream vs unexpected error? I'm just curious to know what you use this for.
Sure, we're doing live video streaming. We want to distinguish when the connection is closed because the live stream has ended (show an "thanks for watching" screen), versus an unexpected error (show an error screen with debug code).
Makes sense, though this is for an entire session (see ). Here we're discussing individual streams.
I'm finding the mention of CONNECTIONCLOSE slightly confusing since this thread is about stream resets. The JS API doesn't mention if CONNECTIONCLOSE is a transport-level or application-level close, it really should. The HTTP-based WebTransports support graceful connection close via GOAWAY. Applications built on WebTransport might be able to harness these properties, or they might need to create a control channel per session that could then behave exactly how they want, without the overhead of IETF registries.
Oh sorry, for some reason I thought this was for the entire connection. Resetting a stream with an error code is less useful, but again it's in the . RESET_STREAM is useful for my application because the streams transfer a large amount of data, which may be blocked on the network, but I don't have a use-case for application error codes at the moment.
Just to close the loop here. We talked about this in the context of W3C and decided that we'd like to have some number of error code points just for web transport. 256 was the initial suggestion; 100 might work; 31 was considered too small. NAME pointed out that we can play FizzBuzz and step carefully around the reserved greasing points so that a contiguous block is presented to applications even if the underlying code points are not contiguous.
FWIW, where I said there is already an issue for it URL
We discussed this at May 2021 interim, and there appeared to be an agreement in the room that we should do that. I'll write up a PR with some set of 256 points.

If a peer receives a RESETSTREAM message before it receives the first few bytes of the stream, then it is unable associate the RESETSTREAM with a protocol or session. This can occur if the STREAM packet is lost but the RESET_STREAM is not. As a consequence, if a WebTransport client closes a stream with an error code, then it's not guaranteed to be received by the server. Worse yet, a reset client-initiated bidirectional stream may be confused for a HTTP/3 request and cause intended consequences.
Can you give a more concrete example of when this is a problem? You are saying the client opened a unidirectional or bidirectional WT stream, sent some data, then reset it. The server receives only the reset, or some fraction of the data but not enough to figure out which session the stream belongs to. I think this is fine and the server just discards any partial data on this stream. If the application needs to receive the data (even just an error code) in the stream, then the client shouldn't reset it, but instead, send some application level close signal that is delivered reliably on the stream. I don't see how an H3 server could act on any stream data from the client without seeing the beginning of the stream, so I don't think there's much concern about this being served as an H3 request.
Sure. I suppose the problem is the reliable delivery of error codes. If the application closes a stream with an integer code via the , then I would expect that code to be reliably delivered to the other peer. This ambiguous RESET_STREAM case opens the possibility of the code not being associated with a WebTransport session, and thus not delivered, depending on packet loss.
Iiuc the problem is if the stream is reset before the Web Transport frame is processed (as far the current spec says). That frame associates the stream to the web transport session. A peer that receives the RESET_STREAM know something was cancelled but not whether it was a normal request or a webtransport stream. This highlights a challenge with retconning what bidirectional streams mean for a H3 stack.
I can construct an application where it's important that the peer knows about every stream that gets created, even if it is reset before anything interesting happens, but it strikes me as a bit fringy.

Can you give a concrete example where the WT endpoint missing the reset stream entirely is problematic?
The only example I can think of relates to session pooling and wanting different concurrency limits in sessions. Since we decided to focus on single sessions for now, my example I'd moot. I'd be interested to know Luke's example
Ironically, the best example is an application implementing a replacement for MAX_STREAMS. Peers can't set a cumulative limit if they disagree on the number of streams created. ex. peer A creates and resets a stream, so it thinks 10 have been created in total, but packet loss could cause peer B to think only 9 have been created in total. This can eventually cause a deadlock. And yeah, it's pretty easy to imagine an application that uses stream resets. The WebTransport API makes stream closure seem reliable, when really there's a small chance that it gets silently dropped.
This seems like another case of where a "session layer" over QUIC would assist. The trouble is, in my limited understanding of the W3C WebTransport API, that it wants to use a QUIC transport feature to manage WebTransport sessions. It is going to be let down by the fact the transport behaves differently than it wishes. draft-ietf-webtrans-http3-00 defines the WEBTRANSPORT_STREAM HTTP/3 frame for initiating WebTransport streams. So it probably needs an equivalent frame for closing WebTransport streams. This could be sent on the stream itself, on a new "webtransport session control stream", or on the global control stream.
By 'on the stream itself', do you mean on the CONNECT stream that established the session? The current draft disables framing on WT streams. It could be a message like QPACK, where streams that are cancelled have an application level signal.
No. If I understand (and that's a big if) the design of draft-ietf-webtrans-http3-00 requires step 1) use extended CONNECT on client bidi stream to create a WebTransport session step 2) create WebTransport stream on different client bidi stream using WEBTRANSPORT_STREAM frame URL My suggestion wasn't about retiring WebTransport sessions, but retiring streams robustly at the application layer. If you created a stream using an H3 frame, retire it with an H3 frame.

Although we adopted draft-ietf-webtrans-http3-00, I;m not sure how much of the design is appropriate/relevant to the non-pooling constraints we have added. So i guess my current understanding could be subject to change.
The current draft uses a 'TV' frame on streams created in step 2) that makes sending additional frames on those streams impossible. I'm suggesting we could use the stream created in step 1) as a "webtransport session control stream", if needed.
Ah yes, I overlooked that. In that case I agree
I was thinking about how to make those more reliable. One way would be to send a capsule with something like "stream X associated with this transport has been reset". That doesn't work, because the peers don't have consistent stream IDs across possible HTTP proxies. I think the approach we should probably go with is "stream resets are usually not reliable". As an API caveat, we should make sure that when the connection is dedicated, all resets with WebTransport error codes are followed to the client, since those are unambiguous.
This was fixed in .