Repository navigation
HTTP/2 ServerResponse.destroy() has the same effect as ServerResponse.end() #35302
Description
Activity
I just encountered this issue as well. You can workaround this issue by adding any error to the
destroy()call.Once you do that, you will trigger another bug in the client, where
endis emitted beforeerror:stream end stream errorCalling
destroy()without an error on an active stream should probably end up sending aRST_STREAMframe with code 8. to signal that it was aborted.Reacted by Szymon Marczak- addedhttp2Issues and PRs related to the http2 subsystem.Issues and PRs related to the http2 subsystem.
on Sep 26, 2020 Hmm, this is actually already tested against here (introduced in #15074):
node/test/parallel/test-http2-compat-serverresponse-destroy.js
Lines 44 to 51 in b15ed65
{ const req = client.request(); req.on('response', common.mustNotCall()); req.on('error', common.mustNotCall()); req.on('end', common.mustCall()); req.on('close', common.mustCall(() => countdown.dec())); req.resume(); } Except, the test is wrong! – and doesn't match the equivalent HTTP1 behaviour (which will emit an
'aborted'event in the client)I tried messing with the _destroy() implementation in
core.js, but when I add aNGHTTP2_CANCELcode to the close, the client will just ignore the code and treat it as a normal stream end! So I guess we are up to 3 bugs now...Actually, the aborted comment is plain wrong, since the aborted event is only emitted when the writable side is still open (which it won't be). So this logic just loses all such aborts:
node/lib/internal/http2/core.js
Lines 2200 to 2204 in ff02801
// RST code 8 not emitted as an error as its used by clients to signify // abort and is already covered by aborted event, also allows more // seamless compatibility with http1 if (err == null && code !== NGHTTP2_NO_ERROR && code !== NGHTTP2_CANCEL) err = new ERR_HTTP2_STREAM_ERROR(nameForErrorCode[code] || code); Reacted by Szymon MarczakFYI, I made an attempt at fixing all 3 bugs in #35209.
github-actions commented
on Jun 27, 2026 on Jun 27, 2026 – with GitHub ActionsContributorMore actionsThis issue has been marked as stale due to 210 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.- addedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Jun 27, 2026 github-actions commented
on Jul 28, 2026 on Jul 28, 2026 – with GitHub ActionsContributorMore actionsThis issue has been automatically closed after 30 days of inactivity following its stale status (no activity for a total of 120 days).
If this is still relevant, feel free to reopen it or leave a comment with additional details so we can continue the discussion.
Linux solus 5.6.19-158.current #1 SMP PREEMPT Sun Jul 26 14:17:01 UTC 2020 x86_64 GNU/LinuxWhat steps will reproduce the bug?
Note: it works as expected when the method is e.g. POST and
stream.end()is not called.How often does it reproduce? Is there a required condition?
Always.
What is the expected behavior?
abortedor anerrorevent.What do you see instead?
endevent is emitted.