Change:
See QPACK for more details. A server MUST NOT use a Push ID that is larger than the client has <del> provided in a MAX_PUSH_ID frame (frame-max-push-id) and MUST NOT use the same Push ID in multiple PUSH_PROMISE frames.  A client MUST treat receipt of a PUSH_PROMISE that contains a larger Push ID than the client has advertised or a Push ID which has already been promised as a connection error of type HTTP_MALFORMED_FRAME. </del> <ins> provided in a MAX_PUSH_ID frame (frame-max-push-id).  A client MUST treat receipt of a PUSH_PROMISE frame that contains a larger Push ID than the client has advertised as a connection error of HTTP_ID_ERROR. A server MUST NOT use the same Push ID in multiple PUSH_PROMISE frames.  A client MUST treat receipt of a Push ID which has already been promised as a connection error of type HTTP_ID_ERROR. </ins> If a PUSH_PROMISE frame is received on the control stream, the client MUST respond with a connection error (errors) of type

Discussion:
Implements suggestions from
Updated to replace HTTPLIMITEXCEEDED and HTTPPUSHIDERROR with the single error HTTPID_ERROR.
There are presently a few cases where the Push ID can be used incorrectly. The table shows current error codes, proposes replacing the HTTPDUPLICATEPUSH with an HTTPPUSHIDERROR code, and replaces use of HTTPMALFORMED frame. Note, on I suggested a slightly different solution to replace HTTPMALFORMED FRAME, but I think this is a better path.
To me it seems that having an error code for specific part of push (i.e. ID of push-related information being incorrect) a bit too detailed. I think it sticks out, because we do not have things like "IDERROR, STREAMIDERROR. Also, using PUSHIDERROR in some cases while using MALFORMEDFRAME in others seems confusing. I think we might want to consider doing either of the two: Use PUSHIDERROR (or a generic error code for push) for all the push-related errors. This makes sense if we consider push as an optional feature of HTTP/3 Introduce IDERROR that captures all the limit and ID errors.
Thanks NAME The proposal is a bit of a compromise, so I agree with some of the points that you make. I like your idea of replacing HTTPLIMITEXCEEDED with HTTPIDERROR. I think it solves the issue in the most general way and doesn't change the protocol mechanics. What follows is the response I made first, before coming to that agreement :) Right. The difference here is that H3 frames only reference the stream and placeholder ID spaces, they don't control them. So, if the peer references an ID that doesn't exist then respond with HTTPLIMITEXCEEDED. Multiple references to the same ID is a little different, its ok to reuse placeholder ID (as long as the above condition holds, and you create a semantically valid PRIORITY frame). The transport spec discusses reuse of stream IDs at that layer; in H3 we only use stream ID for PRIORITY and GOAWAY - this has similar restrictions. However, server push is a little different because it's ID space is managed by the MAXPUSHID frame. The three errors that use HTTPPUSHIDERROR are unique to push.

However, if we modified HTTPLIMITEXCEEDED to cover exceeding limits and incorrect ID usage (call it HTTPID_ERROR) I think that would work.
I updated the PR with the above, so that we can see what it looks like.
I'm not totally sold on this, but I'm having trouble articulating what it is that doesn't flow for me. I suspect that means I don't actually disagree, I just need some time to wrap my head around it.
We merged so I'm closing this as completed.