Replies: 4 comments 1 reply
|
I'd suggest to enable the In combination, extending the Can you provide a small |
|
unfortunately I'm not close to having an easy reproduction I do have some more leads, this time I saw Fetch failed TypeError: fetch failed [cause]: InformationalError: HTTP/2: "GOAWAY" frame received with code 0 I think this is nginx shutting down a persistent connection, and the POST request colliding with this. Either undici or nginx isn't handling this nicely. https://trac.nginx.org/nginx/ticket/2224 suggests there is a two stage GOAWAY to do a nice shutdown, and even if undici properly implements that, it seems nginx has decided that they won't. Maybe I should try to just do a dummy GET first just to absorb a broken connection, and see if the POSTs stop failing then |
|
The
A dummy GET can be a useful probe too, but I would make it a separate variant: if it fails before the final POST, it turns the intermittent failure into an earlier observable signal rather than masking it. A minimal repro is still the ideal end state, but this matrix should make a long-running reproduction much more informative. |
|
Following up on the MRE request — I built a local HTTP/2 lab to try to reproduce the failure, testing exactly the nginx behavior from trac.nginx.org/nginx/ticket/2224 (a single GOAWAY, no two-stage shutdown). Environment: Node v24.14.1, undici 8.5.0 (your version), 8.7.0 and 8.10.0, TLS with ALPN Scenarios tested, each on all three versions:
Result: I could not make any of these hang or fail — on 8.5.0, 8.7.0 or 8.10.0. In-flight requests complete, refused streams are replayed on a fresh session (my server log shows That negative result is itself a clue: combined with your symptoms (hangs only after a ~60 min idle, from two different networks, and every request to that origin hanging — including fresh GETs — while other origins work), I'd now point less at GOAWAY handling and more at a silently dead connection: a NAT/conntrack entry (or a middlebox) expiring during the long idle window. The TCP connection then looks open on both ends but packets go nowhere — which produces exactly your pattern: requests that hang until your 90 s abort fires, with no error from the client itself. It would also explain why the version change to 8.7.0 only "helped a bit" (timing luck) rather than fixing it. Two cheap experiments to confirm or kill this hypothesis:
If even with a warm path you still see hangs, one more discriminator: at hang time, create a fresh |
Uh oh!
There was an error while loading. Please reload this page.
(I'm not ready to make an issue yet as my problem takes a long time to reproduce, so i'm checking to see if anyone has pointers where to look/what to try to isolate the issue)
I'm using node26.4 on mac with undici 8.5.0. I've built a backupscript that
This last POST always hangs. I've set a 90second abort on each attempt and retry 15 times, I'll just get 15 AbortErrors.
If I connect to the process during the POST hangs (kill -USR1, chrome devtools) I'll see any fetch() to the same server hang (whether POST or GET), but I can fetch other servers just fine. So I'm suspecting this has to do with unidici keeping connections open for reuse, and something timing out on either the server or the client making the connection unusable. Or perhaps it's NAT timing out the unused connection (I've tried from 2 different locations/behind 2 routers, both home and office). I can't pin it down yet.
Switching to a manually installed undici 8.7.0 seems to help a bit - now I'm at only 3 AbortErrors and the 4th retry succeeds, but it'll be a few more long testruns before I can be sure it actually makes a difference - maybe I just got lucky.
Any hints on how to further isolate this? Can I reset the persistent connections, or limit their duration, to see if that changes anything and. Any flag that might provide insight on what exactly happens on the HTTP2 layer?
All reactions