Change:
Frame types of the format "0x1f * N + 0x21" for integer values of N are reserved to exercise the requirement that unknown types be ignored (extensions).  These frames have no semantics, and can be <del> sent when application-layer padding is desired.  They MAY also be sent on connections where no data is currently being transferred. Endpoints MUST NOT consider these frames to have any meaning upon receipt. </del> <ins> sent on any open stream when application-layer padding is desired. They MAY also be sent on connections where no data is currently being transferred.  Endpoints MUST NOT consider these frames to have any meaning upon receipt. </ins> The payload and length of the frames are selected in any manner the implementation chooses. <ins> Frame types which were used in HTTP/2 where there is no corresponding HTTP/3 frame have also been reserved (iana-frames).  These frame types MUST NOT be sent, and receipt MAY be treated as an error of type HTTP_UNEXPECTED_FRAME. </ins> 8. QUIC allows the application to abruptly terminate (reset) individual

Discussion:
So it turns out that there are two different things called "reserved frame types" in HTTP/3. There are the types reserved for greasing, and there are the types reserved to minimize confusion at code point overlap with HTTP/2. This PR makes three changes, separable if there's controversy: Adds "Reserved" to the frame type table, pointing to the Reserved Types section, and indicates they can be sent on all stream types. Clarifies in the Reserved section that GREASE frames can be sent on any open stream Calls out the reserved-for-H2 types as MUST NOT send, MAY error. Clarifies in the Extensibility section that, while you ignore frame types you don't know, you don't ignore that it wasn't the frame you were expecting if a particular type was required to be in that position.
We've had a long standing requirement that stream (see Section 3.2.1) by each peer By the way I interpret this, I put a check in my implementation that doesn't permit any frame until SETTINGS is received. Am I interpreting things correctly? It would be more consistent to allow reserved frame types to appear at any point on any stream that carries frames. However, I'm fine with this requirement as is but it means there is a little more effort needed to handle reserved frame types across streams.
In our implementation we are interpreting this in the same way: any frame on the control stream received before SETTINGS is a connection error. Even reserved frame types. In general the way we handle this is by discarding frame types that are forbidden rather than checking frame types that are allowed on each stream. Here is a snippet from our code. In this way we avoid the extra effort needed to handle reserved frame types that you mentioned, if I am reading your statement correctly. Basically, some frame types are explicitly disallowed. All other frame types are equal, reserved or non-reserved. Do you foresee an extension possibly benefiting from sending a frame before settings ?
Thanks NAME you made me realise I asked the question wrong. This is about reserved and non-core frames. Section 7 says: extensible protocol elements. Implementations MUST discard frames ... I have no strong use case for delivering frames before SETTINGS. But I worry it falls into a slight grey area that might affect interop.

I think the correct answer is that the control stream is special case and we should clarify that in Section 7.
My preference goes to retaining the requirement as-is. This is the way H2 has worked, and I am not sure if there is a practical reason to change. FWIW, we have a similar requirement for PRIORITY frame too, which I'm also fine with: A PRIORITY frame received after other frames on a request stream MUST be treated as a connection error of type HTTPUNEXPECTEDFRAME ().
Ooh yeah, that's a good catch too. Table 1 in section 4 seems to actually highlight this behaviour with the notation. And we sort of have some text that captures this in section 4: We could add tweaks or further guidance to this paragraph ( in a PR that also that makes things explicitly clear .
On receipt, reserved is irrelevant -- it's just an unknown frame type. The reservation is simply to permit senders to generate unknown frame types without accidental collision to a real extension the client might support. So the question is whether "ignoring" unknown frame types means pretending that they weren't even there, and therefore the subsequent frame might still be the first frame on the stream. I'm inclined to say no -- you take no action on a frame you don't recognize, but that doesn't mean that the next frame was the first frame.
I think the overview table in HTTP/3 section 4 should probably also include reserved frame types. This will make it clear what streams these frames can appear on.