-
Notifications
You must be signed in to change notification settings - Fork 90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
EPIPE write, ECONNRESET issues when switch to nodejs 20 #177
Comments
Oooh, that sounds very interesting! I haven't seen this before myself, and Mockttp's own tests seem to run fine in 20.16.0 so I'm not sure exactly what would cause this. Is there any pattern to which tests fail? Is there anything notable about those tests? If you try using other Node versions (older Node v20 versions, or Node v22) do those fail in the same way? If not, it would be really interesting to try a few different versions and see if you can work out exactly which version is breaking this for you. |
Hi @pimterry, Indeed a very interesting issue it is 🙂 Regarding your questions:
I tried version 20.0.0 and it is not working right away, so seems that the issue is appearing from very beginning of the node 20 version. I also tried 22.6.0 and it fails the tests in the same way. And again the latest 18.x version fixes everything immediately. I also use the latest to date
There are two patterns usually:
expect(received).toEqual(expected) // deep equality
- Expected - 3
+ Received + 7
Object {
"details": Object {
- "messages": Array [],
- "returnCode": 0,
+ "connectionCode": "ECONNRESET",
+ "httpStatusCode": undefined,
+ "messages": Array [
+ "read ECONNRESET",
+ ],
},
- "status": "OK",
+ "status": "ERROR",
+ "type": "CONNECTION_ERROR",
}
10244 | )(packageName)(packageOptions);
10245 | // assert
> 10246 | expect(createPackageResult).toEqual({
| ^
10247 | status: ResponseStatus.OK,
10248 | details: {
10249 | returnCode: 0, These tests usually use await mockServer.forAnyRequest().thenJson(
200,
{
data: [],
messages,
reports: {},
returnCode,
},
{
version: '2.5',
'content-type': 'application/json',
}
);
expect(received).toBe(expected) // Object.is equality
Expected: true
Received: false
6726 | const seenRequests = await endevorEndpoint.getSeenRequests();
6727 | const calledOnce = seenRequests.length === 1;
> 6728 | expect(calledOnce).toBe(true);
| ^
6729 |
6730 | expect(isErrorEndevorResponse(generateResult)).toBe(false);
6731 | }); This one happens usually with the |
Ok, that's very useful thanks. I think it's likely that this is a Node bug (or intentional breaking change that's causing issues), but unfortunately I'm also a Node maintainer, so I can't really pass the buck here 😆, and whether the fix is in Node or Mockttp it'd be useful to know exactly what's going on. Can you share more detail about how exactly are you're sending the requests, and any kinds of client configuration there? One thing that has changed a few times in Node during major version bumps is a slow tightening of which kinds of subtly invalid connections or unusual requests are accepted, so it might be that there's something unusual there triggering this. If you test with some v19 versions, does this fail the same way there too? If we can pin this down to a specific version where it breaks then that would reduce the set of possibly related changes in Node significantly, which would be very helpful to understand the issue. Is there any chance you can put together a reproduction of the issue, or share enough code that I can run the tests myself? That would make it very dramatically easier to investigate and fix. |
I think I managed to replicate the same problem on a simpler codebase. Pushed the code here: https://github.com/codurance/mockttp-test This project has two tests, reusing the same server which will start on the same port. The first one passes and the second one fails. I think this also depends on the specific version of Jest used but still looking into that. [update: nope, upgraded everything to latest and it still fails] |
Thanks @jaramir, that's definitely an interesting example. It looks like Any idea why that might be? I know Jest has some weird & wonderful hooks into various internals, I wonder if that might interact with fetch in some unexpected ways somewhere. Adding a bunch of debug logging, it looks like Mockttp doesn't even receive a TCP connection at all in the 2nd test. If you try using a simpler test runner (Node's built-in test runner, or mocha or something) does that work? |
I am not sure if it helps, but to me it seems to be happening on every other test. My setup is Don't want to add a red herring here, cause I am really just a user of both of the libs, just wanted to add a theory to test if you run out of ideas EDIT: I was using node 20, when I downgrade to 16 (just picked random installed prior v19), all tests pass. So now I am quite confident this might be the problem. Not sure how to fix it though :D |
I've removed cross-fetch. It still fails if the first test does two requests: https://github.com/codurance/mockttp-test It works if the port is randomised with I've followed the traffic with Wireshark: what I see is the node build-in fetch reusing the connection used by the first request after sending FIN and before receiving FIN from the server. Edit: this also fails on node 18 so we might have stumbled on an entirely different problem. |
Yep, I can see this too. I think this is a known Node bug via Undici's fetch implementation: nodejs/undici#3492. As you can see from discussion there, it seems you can hit it in other cases, but the fetch case is more common. In short: the client has already received a FIN packet, and so it definitely shouldn't be trying to continue using the connection. It only comes up when there's a very short delay between connection close (triggered by In general this is Mockttp working correctly - the server closes and sends a FIN before It looks like you can fix this by adding a tiny delay after server shutdown (5ms works reliably on my machine) so that the close packets are definitely processed. That's obviously suboptimal of course, since it's a bit arbitrary/flaky and it's an annoying extra step, but it might be useful as another workaround. I'll see if there's anything we can do to improve this here so that waiting for |
Hello,
After the migration to nodejs 20.16.0 from 18.20.4 some of our tests that use Mockttp server started to fail with
EPIPE write
orECONNRESET read
orECONNRESET socket hang up
errors. We have around 200 tests in general and only some of them are affected. A weird part is that if to run failed tests individually they are passing, which makes me think that it may be related to some parallel running issues or race conditions. We use Jest as a test runner.Any help would be appreciated. Thanks!
The text was updated successfully, but these errors were encountered: