undici
undici copied to clipboard
`fetch` may try to use a closed connection
Version
v22.6.0
Platform
Darwin MacBook-Pro-6.local 23.5.0 Darwin Kernel Version 23.5.0: Wed May 1 20:12:58 PDT 2024; root:xnu-10063.121.3~5/RELEASE_ARM64_T6000 arm64
Subsystem
http
What steps will reproduce the bug?
// fetch-test.js
const {createServer} = require('node:http');
const port = 8080;
const url = 'http://localhost:' + port;
const server = createServer((req, res) => res.end()).listen(port, async () => {
await fetch(url);
server.closeIdleConnections();
setImmediate(async () => {
await fetch(url); // Throws TypeError with cause UND_ERR_SOCKET or ECONNRESET
server.close();
});
});
How often does it reproduce? Is there a required condition?
Reproduces consistently for me but the error cause
varies roughly evenly between ECONNRESET
and UND_ERR_SOCKET
(details below)
What is the expected behavior? Why is that the expected behavior?
fetch
creates a new connection if there are none open, and the request succeeds.
What do you see instead?
node fetch-test.js
node:internal/deps/undici/undici:13178
Error.captureStackTrace(err);
^
TypeError: fetch failed
at node:internal/deps/undici/undici:13178:13
at async Immediate.<anonymous> (/Users/robhogan/workspace/fetch-test.js:11:5) {
[cause]: SocketError: other side closed
at Socket.<anonymous> (node:internal/deps/undici/undici:6020:28)
at Socket.emit (node:events:532:35)
at endReadableNT (node:internal/streams/readable:1696:12)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
code: 'UND_ERR_SOCKET',
socket: {
localAddress: '::1',
localPort: 57996,
remoteAddress: undefined,
remotePort: undefined,
remoteFamily: undefined,
timeout: undefined,
bytesWritten: 338,
bytesRead: 122
}
}
}
Node.js v22.6.0
OR
node fetch-test.js
node:internal/deps/undici/undici:13178
Error.captureStackTrace(err);
^
TypeError: fetch failed
at node:internal/deps/undici/undici:13178:13
at async Immediate.<anonymous> (/Users/robhogan/workspace/fetch-test.js:11:5) {
[cause]: Error: read ECONNRESET
at TCP.onStreamRead (node:internal/stream_base_commons:218:20) {
errno: -54,
code: 'ECONNRESET',
syscall: 'read'
}
}
Node.js v22.6.0
Additional information
This seems to be quite sensitive to timing/the event loop in a way I haven't pinned down.
- The
setImmediate
(orsetTimeout(cb, 0)
) is required to reproduce the issue. - Adding another
setImmediate
before the secondfetch
makes it succeed. - Adding
{headers:{'Connection': 'close'}}
to the first request succeeds.