You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
HTTP2 Requests hang upon receiving 'Stream closed with error code NGHTTP2_INTERNAL_ERROR' #2675
If node closes a http2stream with NGHTTP2_INTERNAL_ERROR, the await dispatch in httpNetworkFetch() in fetch/index.js will never resolve
Reproducible By
The tricky part about reproducing is understandably getting node to throw this error. Reproductions seem related to sending many large http2 post requests via the fetch api to the same endpoint while the event loop is busy.
Expected Behavior
The promise is rejected rather than left unfulfilled.
Logs & Screenshots
With NODE_DEBUG=http2 I can see code 2 (NGHTTP2_INTERNAL_ERROR) being thrown
If i add a call to errorRequesthere in writeH2() i can see the following error and my expected behavior of rejecting the promise
[2024-01-30T22:18:42.122Z] [phase_0 saas_local_webhook] [err] [1/30/2024, 5:18:41 PM] [PLATFORM_FETCH] Error resulted from fetch for request POST
{
"stack": "TypeError: fetch failed\n at Object.fetch9 (/nix/store/qwj14ylfz8y3ji41rgzssgk25i4wp749-esbuild_node/depengine_worker.js:31730:19)\n at processTicksAndRejections (node:internal/process/task_queues:96:5)",
"message": "fetch failed",
"cause": {
"stack": "Error [ERR_HTTP2_STREAM_ERROR]: Stream closed with error code NGHTTP2_INTERNAL_ERROR\n at new NodeError (node:internal/errors:372:5)\n at ClientHttp2Stream._destroy (node:internal/http2/core:2339:13)\n at _destroy (node:internal/streams/destroy:109:25)\n at ClientHttp2Stream.destroy (node:internal/streams/destroy:71:5)\n at Http2Stream.onStreamClose (node:internal/http2/core:549:12)",
"message": "Stream closed with error code NGHTTP2_INTERNAL_ERROR"
}
}
Primary question
Why is errorRequest used only in the frameError handler and not the error handler? How else should this promise end up rejected?
Yeah, that's a good catch and indeed a bug. Both belong to a single stream that is most likely tight to a single request/response lifecycle for fetch and undici itself.
There's no reason to reuse the same, it was most likely left over we forgot to check.
Would you like to send a PR? It might be hard, but let's see if we can add some tests.
but just calling errorRequest on error in client.js's stream error handler results in a ClientDestroyedError seemingly if the client is closed without the body having been consumed eg the following will throw
I opened a pr thank you very much for your support and explanations I hope I did it right if you have any suggestions please do not hesitate @metcoder95@jackschu
Activity
metcoder95 commentedon Jan 31, 2024
Yeah, that's a good catch and indeed a bug. Both belong to a single stream that is most likely tight to a single request/response lifecycle for
fetchandundiciitself.There's no reason to reuse the same, it was most likely left over we forgot to check.
Would you like to send a PR? It might be hard, but let's see if we can add some tests.
mertcanaltin commentedon Jan 31, 2024
I can take care of this issue if it's appropriate
jackschu commentedon Jan 31, 2024
Sure I can look at adding this patch + some test coverage, It'll likely be outside of my working hours so may be a week or so
jackschu commentedon Feb 6, 2024
I took a swing at this but am running into some trouble around
ClientDestroyedErrorCurrently something like this would result in the promise hanging, I don't think that's correct, and should instead result in a reject
but just calling
errorRequeston error inclient.js's stream error handler results in aClientDestroyedErrorseemingly if the client is closed without the body having been consumed eg the following will throwAny advice around how to handle this?
metcoder95 commentedon Feb 6, 2024
Can you provide the full
Minimum Reproducible Example?
Feel free to also open a PR and we can iterate from it
mertcanaltin commentedon Feb 7, 2024
I opened a pr thank you very much for your support and explanations I hope I did it right if you have any suggestions please do not hesitate @metcoder95 @jackschu
Sarthak-Shreshtha01 commentedon Sep 25, 2026
Happy to take a look at this if it's still open — let me know if someone is already on it.
metcoder95 commentedon Sep 28, 2026
go for it