-
Notifications
You must be signed in to change notification settings - Fork 531
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
SocketError: other side closed #583
Comments
@ShrimpAIO do you have an example with another HTTP client of this working? |
|
`node:internal/process/promises:245 SocketError: other side closed |
So from what I can gather these other HTTP clients may be automatically adding things to the request for you. I'd recommend logging the complete request from something like |
I've made some progress but still not working with these particular proxies. 400 Bad Request400 SocketError: other side closed The IP's are 100% authenticated as the superagent code works both on Ubuntu and Windows.. For context, the code being tried now is as below; |
Seems like another proxy provider refuses to work; |
Maybe this is something not yet achievable in Undici see #569 |
And #568 might help you too |
Ok; |
This also happened to me when making a normal request to for example "http://nvidia.com" using the example from the Quickstart. I do get some response but after that my app crashes: response received 302
headers {
location: 'http://www.nvidia.com/',
'content-type': 'text/html',
'cache-control': 'private',
connection: 'close'
} The application crashes on: events.js:292
throw er; // Unhandled 'error' event
^
SocketError: other side closed
at Socket.onSocketEnd (/Users/<my-username>/<my-project>/node_modules/undici/lib/client.js:916:22)
at Socket.emit (events.js:327:22)
at endReadableNT (internal/streams/readable.js:1327:12)
at processTicksAndRejections (internal/process/task_queues.js:80:21)
Emitted 'error' event on RequestResponse instance at:
at emitErrorNT (internal/streams/destroy.js:106:8)
at emitErrorCloseNT (internal/streams/destroy.js:74:3)
at processTicksAndRejections (internal/process/task_queues.js:80:21) {
code: 'UND_ERR_SOCKET' |
Do you have the same problem with 4.0.0-alpha.2? |
Just tried and this still happend with 4.0.0-alpha.2 |
Can you please provide a repro example? |
I had a pretty similar error:
I build a small reproduction, its just requesting a lot of files one by one from cloudfront. Note: this does happen consistently but it might take a few requests. Edit: Edit2: |
|
@MoritzLoewenstein Could you use a Node.js server to reproduce? |
Hey, I added a node server. The issue is indeed an invalid Content-Length header, if I don't set the Content-Length header on the server I cant reproduce the issue. |
Do you know what's the value of this? |
When I dont set the Content-Length header, node will set the Transfer-Encoding header to chunked (= no Content-Length header). |
Can you prepare an example to reproduce the problem? You can also use a |
My provided example should be sufficient to show the problem: https://github.com/MoritzLoewenstein/undici-fetch-repro I investigated a bit more: When the code enters here is the parser printed in this function:
|
It's not enough for a unit test. |
Alright, I will see if I can narrow it down. |
Thanks! Tracking down those conditions is hard :(. |
The reason undici crashes is an incorrect One more thing I found out in the process, undici will keep the node process open if Current reproduction with server & files is here: https://github.com/MoritzLoewenstein/undici-fetch-repro |
Ok, I have written a test that will fail, but I think I cant push it because of that. here is the code for the test:test('dont crash on unexpected Transfer-Encoding Header', async (t) => {
t.plan(2)
const server = createServer((req, res) => {
res.setHeader('Content-Type', 'text/plain')
res.removeHeader('Connection')
res.removeHeader('Keep-Alive')
res.removeHeader('Transfer-Encoding')
const str = 'Chunked Transfer Encoding Test'
res.write(str.repeat(832))
res.end(str)
})
t.teardown(server.close.bind(server))
server.listen(0, async () => {
const client = new Client(`http://localhost:${server.address().port}`)
t.teardown(client.close.bind(client))
process.on('uncaughtException', () => {
t.fail('uncaughtException happened')
})
try {
await client.request({
path: '/',
method: 'GET'
})
t.pass('request successful')
} catch (err) {
t.pass('error happened')
} finally {
process.removeListener('uncaughtException')
}
})
}) |
Your test does not run successfully, it has some issues with promises, callbacks and how tap needs things laid out. However, I have adapted your test to run and it passes on master (see #822). My understanding is that this is fixed. |
(You can push a failing test with |
Im sorry for the incorrect test, but the issue still happens on rc5. Apparently the issue only occurs when not doing anything with the response body, because you called
I dont know how common this is but my original use case was to just read the response headers, status code etc and doing nothing with the body. |
You need to consume or destroy the response body. I think the docs mention this. |
I wasnt aware of that and couldnt find it in the docs, but if that is the case it should be handled in undici-fetch i guess? |
Yea I can’t find it either now. Maybe got lost when we did the docs overhaul. PR welcome! All response bodies must always be fully consumed or destroyed. |
I'm still having this bug with 4.0.0-rc.7, what is wrong? import type { RequestHandler } from '@sveltejs/kit';
import pkg from 'undici';
const { Pool } = pkg;
// process.env.API_ORIGIN would be killed by vite (bug), so hack
const client = new Pool(
process['env']['API_ORIGIN'] ?? 'http://localhost:6543',
);
export const post: RequestHandler = async req => {
// We are waiting this https://github.com/sveltejs/kit/issues/1563
// to complete, then we must switch to previous implementation, preserving compression etc
try {
const headers: Record<string, string | string[]> = {
'content-type': 'application/json; charset=utf-8',
};
const data = await client.request({
path: '/v1/graphql',
method: 'POST',
body: JSON.stringify(req.body),
headers,
});
let strBody = '';
for await (const chunk of data.body) {
strBody += chunk;
}
const allowedHeaders = [
'content-encoding',
'content-type',
];
const headersOut: Record<string, string> = {};
for (const allowedheader of allowedHeaders) {
const headerValue = data.headers[allowedheader] as string;
if (headerValue != null) {
headersOut[allowedheader] = headerValue;
}
}
return {
headers: headersOut,
body: strBody,
};
} catch (e) {
console.error('ERROR: error occured at graphql.js handler', e.message);
console.error(e);
throw e;
}
}; PS: |
I'm facing a similar error, but with
|
Hi there, still experiencing this issue on undici v5.22.1. Any resolution here? |
@ronag @mcollina Here's my findings so far (this occurs when you run a I modified the culprit of this error being thrown here: function onSocketEnd () {
const { [kParser]: parser } = this
if (parser.statusCode && !parser.shouldKeepAlive) {
// We treat all incoming data so far as a valid response.
parser.onMessageComplete()
return
}
+ console.log('parser', parser);
+ console.log('socket info', util.getSocketInfo(this));
+ console.log('this', this);
+ // this causes the error to be thrown
util.destroy(this, new SocketError('other side closed', util.getSocketInfo(this)))
} The output of parser <ref *1> Parser {
llhttp: [Object: null prototype] {
memory: Memory [WebAssembly.Memory] {},
_initialize: [Function: 9],
__indirect_function_table: Table [WebAssembly.Table] {},
llhttp_init: [Function: 10],
llhttp_should_keep_alive: [Function: 65],
llhttp_alloc: [Function: 12],
malloc: [Function: 70],
llhttp_free: [Function: 13],
free: [Function: 72],
llhttp_get_type: [Function: 14],
llhttp_get_http_major: [Function: 15],
llhttp_get_http_minor: [Function: 16],
llhttp_get_method: [Function: 17],
llhttp_get_status_code: [Function: 18],
llhttp_get_upgrade: [Function: 19],
llhttp_reset: [Function: 20],
llhttp_execute: [Function: 21],
llhttp_settings_init: [Function: 22],
llhttp_finish: [Function: 23],
llhttp_pause: [Function: 24],
llhttp_resume: [Function: 25],
llhttp_resume_after_upgrade: [Function: 26],
llhttp_get_errno: [Function: 27],
llhttp_get_error_reason: [Function: 28],
llhttp_set_error_reason: [Function: 29],
llhttp_get_error_pos: [Function: 30],
llhttp_errno_name: [Function: 31],
llhttp_method_name: [Function: 32],
llhttp_status_name: [Function: 33],
llhttp_set_lenient_headers: [Function: 34],
llhttp_set_lenient_chunked_length: [Function: 35],
llhttp_set_lenient_keep_alive: [Function: 36],
llhttp_set_lenient_transfer_encoding: [Function: 37],
llhttp_message_needs_eof: [Function: 63]
},
ptr: 141936,
client: <ref *2> Client {
_events: [Object: null prototype] {
drain: [Function: onDrain],
connect: [Function (anonymous)],
disconnect: [Function (anonymous)],
connectionError: [Function (anonymous)]
},
_eventsCount: 4,
_maxListeners: undefined,
[Symbol(kCapture)]: false,
[Symbol(destroyed)]: false,
[Symbol(onDestroyed)]: null,
[Symbol(closed)]: false,
[Symbol(onClosed)]: [],
[Symbol(dispatch interceptors)]: [ [Function (anonymous)] ],
[Symbol(url)]: URL {
href: 'http://localhost:3000/',
origin: 'http://localhost:3000',
protocol: 'http:',
username: '',
password: '',
host: 'localhost:3000',
hostname: 'localhost',
port: '3000',
pathname: '/',
search: '',
searchParams: URLSearchParams {},
hash: ''
},
[Symbol(connector)]: [Function: connect],
[Symbol(socket)]: Socket {
connecting: false,
_hadError: false,
_parent: null,
_host: 'localhost',
_closeAfterHandlingError: false,
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 4,
_maxListeners: undefined,
_writableState: [WritableState],
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
write: [Function: writeAfterFIN],
[Symbol(async_id_symbol)]: 144,
[Symbol(kHandle)]: [TCP],
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: null,
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kCapture)]: false,
[Symbol(kSetNoDelay)]: true,
[Symbol(kSetKeepAlive)]: true,
[Symbol(kSetKeepAliveInitialDelay)]: 60,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0,
[Symbol(no ref)]: false,
[Symbol(writing)]: false,
[Symbol(reset)]: false,
[Symbol(blocking)]: false,
[Symbol(error)]: null,
[Symbol(parser)]: [Circular *1],
[Symbol(client)]: [Circular *2],
[Symbol(socket request counter)]: 0,
[Symbol(maxRequestsPerClient)]: undefined
},
[Symbol(pipelining)]: 1,
[Symbol(max headers size)]: 16384,
[Symbol(default keep alive timeout)]: 4000,
[Symbol(max keep alive timeout)]: 600000,
[Symbol(keep alive timeout threshold)]: 1000,
[Symbol(keep alive timeout)]: 4000,
[Symbol(server name)]: null,
[Symbol(local address)]: null,
[Symbol(resuming)]: 0,
[Symbol(need drain)]: 2,
[Symbol(host header)]: 'host: localhost:3000\r\n',
[Symbol(body timeout)]: 300000,
[Symbol(headers timeout)]: 300000,
[Symbol(strict content length)]: true,
[Symbol(maxRedirections)]: undefined,
[Symbol(maxRequestsPerClient)]: undefined,
[Symbol(kClosedResolve)]: null,
[Symbol(max response size)]: -1,
[Symbol(queue)]: [ [Request] ],
[Symbol(running index)]: 0,
[Symbol(pending index)]: 1,
[Symbol(Intercepted Dispatch)]: [Function: Intercept],
[Symbol(connecting)]: false,
[Symbol(needDrain)]: true
},
socket: <ref *3> Socket {
connecting: false,
_hadError: false,
_parent: null,
_host: 'localhost',
_closeAfterHandlingError: false,
_readableState: ReadableState {
objectMode: false,
highWaterMark: 65536,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: [],
flowing: false,
ended: true,
endEmitted: true,
reading: false,
constructed: true,
sync: false,
needReadable: false,
emittedReadable: false,
readableListening: true,
resumeScheduled: false,
errorEmitted: false,
emitClose: false,
autoDestroy: true,
destroyed: false,
errored: null,
closed: false,
closeEmitted: false,
defaultEncoding: 'utf8',
awaitDrainWriters: null,
multiAwaitDrain: false,
readingMore: false,
dataEmitted: true,
decoder: null,
encoding: null,
[Symbol(kPaused)]: null
},
_events: [Object: null prototype] {
end: [Array],
error: [Array],
readable: [Function: onSocketReadable],
close: [Function: onSocketClose]
},
_eventsCount: 4,
_maxListeners: undefined,
_writableState: WritableState {
objectMode: false,
highWaterMark: 65536,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: false,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
afterWriteTickInfo: null,
buffered: [],
bufferedIndex: 0,
allBuffers: true,
allNoop: true,
pendingcb: 0,
constructed: true,
prefinished: false,
errorEmitted: false,
emitClose: false,
autoDestroy: true,
errored: null,
closed: false,
closeEmitted: false,
[Symbol(kOnFinished)]: []
},
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
write: [Function: writeAfterFIN],
[Symbol(async_id_symbol)]: 144,
[Symbol(kHandle)]: TCP {
reading: true,
onconnection: null,
[Symbol(owner_symbol)]: [Circular *3]
},
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: null,
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kCapture)]: false,
[Symbol(kSetNoDelay)]: true,
[Symbol(kSetKeepAlive)]: true,
[Symbol(kSetKeepAliveInitialDelay)]: 60,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0,
[Symbol(no ref)]: false,
[Symbol(writing)]: false,
[Symbol(reset)]: false,
[Symbol(blocking)]: false,
[Symbol(error)]: null,
[Symbol(parser)]: [Circular *1],
[Symbol(client)]: <ref *2> Client {
_events: [Object: null prototype],
_eventsCount: 4,
_maxListeners: undefined,
[Symbol(kCapture)]: false,
[Symbol(destroyed)]: false,
[Symbol(onDestroyed)]: null,
[Symbol(closed)]: false,
[Symbol(onClosed)]: [],
[Symbol(dispatch interceptors)]: [Array],
[Symbol(url)]: [URL],
[Symbol(connector)]: [Function: connect],
[Symbol(socket)]: [Circular *3],
[Symbol(pipelining)]: 1,
[Symbol(max headers size)]: 16384,
[Symbol(default keep alive timeout)]: 4000,
[Symbol(max keep alive timeout)]: 600000,
[Symbol(keep alive timeout threshold)]: 1000,
[Symbol(keep alive timeout)]: 4000,
[Symbol(server name)]: null,
[Symbol(local address)]: null,
[Symbol(resuming)]: 0,
[Symbol(need drain)]: 2,
[Symbol(host header)]: 'host: localhost:3000\r\n',
[Symbol(body timeout)]: 300000,
[Symbol(headers timeout)]: 300000,
[Symbol(strict content length)]: true,
[Symbol(maxRedirections)]: undefined,
[Symbol(maxRequestsPerClient)]: undefined,
[Symbol(kClosedResolve)]: null,
[Symbol(max response size)]: -1,
[Symbol(queue)]: [Array],
[Symbol(running index)]: 0,
[Symbol(pending index)]: 1,
[Symbol(Intercepted Dispatch)]: [Function: Intercept],
[Symbol(connecting)]: false,
[Symbol(needDrain)]: true
},
[Symbol(socket request counter)]: 0,
[Symbol(maxRequestsPerClient)]: undefined
},
timeout: Timeout {
callback: [Function: onParserTimeout],
delay: 300000,
opaque: [Circular *1],
state: 1685997171039
},
timeoutValue: 300000,
timeoutType: 2,
statusCode: 200,
statusText: 'OK',
upgrade: false,
headers: [],
headersSize: 0,
headersMaxSize: 16384,
shouldKeepAlive: true,
paused: true,
resume: [Function: bound resume],
bytesRead: 73102,
keepAlive: 'timeout=5',
contentLength: '73102',
connection: 'keep-alive',
maxResponseSize: -1
} The output of socket info {
localAddress: '127.0.0.1',
localPort: 63749,
remoteAddress: '127.0.0.1',
remotePort: 3000,
remoteFamily: 'IPv4',
timeout: undefined,
bytesWritten: 66,
bytesRead: 76703
} The output of this <ref *1> Socket {
connecting: false,
_hadError: false,
_parent: null,
_host: 'localhost',
_closeAfterHandlingError: false,
_readableState: ReadableState {
objectMode: false,
highWaterMark: 65536,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: [],
flowing: false,
ended: true,
endEmitted: true,
reading: false,
constructed: true,
sync: false,
needReadable: false,
emittedReadable: false,
readableListening: true,
resumeScheduled: false,
errorEmitted: false,
emitClose: false,
autoDestroy: true,
destroyed: false,
errored: null,
closed: false,
closeEmitted: false,
defaultEncoding: 'utf8',
awaitDrainWriters: null,
multiAwaitDrain: false,
readingMore: false,
dataEmitted: true,
decoder: null,
encoding: null,
[Symbol(kPaused)]: null
},
_events: [Object: null prototype] {
end: [ [Function: onReadableStreamEnd], [Function: onSocketEnd] ],
error: [ [Function (anonymous)], [Function: onSocketError] ],
readable: [Function: onSocketReadable],
close: [Function: onSocketClose]
},
_eventsCount: 4,
_maxListeners: undefined,
_writableState: WritableState {
objectMode: false,
highWaterMark: 65536,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: false,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
afterWriteTickInfo: null,
buffered: [],
bufferedIndex: 0,
allBuffers: true,
allNoop: true,
pendingcb: 0,
constructed: true,
prefinished: false,
errorEmitted: false,
emitClose: false,
autoDestroy: true,
errored: null,
closed: false,
closeEmitted: false,
[Symbol(kOnFinished)]: []
},
allowHalfOpen: false,
_sockname: { address: '127.0.0.1', family: 'IPv4', port: 63749 },
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
write: [Function: writeAfterFIN],
_peername: { address: '127.0.0.1', family: 'IPv4', port: 3000 },
[Symbol(async_id_symbol)]: 144,
[Symbol(kHandle)]: TCP {
reading: true,
onconnection: null,
[Symbol(owner_symbol)]: [Circular *1]
},
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: null,
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kCapture)]: false,
[Symbol(kSetNoDelay)]: true,
[Symbol(kSetKeepAlive)]: true,
[Symbol(kSetKeepAliveInitialDelay)]: 60,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0,
[Symbol(no ref)]: false,
[Symbol(writing)]: false,
[Symbol(reset)]: false,
[Symbol(blocking)]: false,
[Symbol(error)]: null,
[Symbol(parser)]: <ref *2> Parser {
llhttp: [Object: null prototype] {
memory: Memory [WebAssembly.Memory] {},
_initialize: [Function: 9],
__indirect_function_table: Table [WebAssembly.Table] {},
llhttp_init: [Function: 10],
llhttp_should_keep_alive: [Function: 65],
llhttp_alloc: [Function: 12],
malloc: [Function: 70],
llhttp_free: [Function: 13],
free: [Function: 72],
llhttp_get_type: [Function: 14],
llhttp_get_http_major: [Function: 15],
llhttp_get_http_minor: [Function: 16],
llhttp_get_method: [Function: 17],
llhttp_get_status_code: [Function: 18],
llhttp_get_upgrade: [Function: 19],
llhttp_reset: [Function: 20],
llhttp_execute: [Function: 21],
llhttp_settings_init: [Function: 22],
llhttp_finish: [Function: 23],
llhttp_pause: [Function: 24],
llhttp_resume: [Function: 25],
llhttp_resume_after_upgrade: [Function: 26],
llhttp_get_errno: [Function: 27],
llhttp_get_error_reason: [Function: 28],
llhttp_set_error_reason: [Function: 29],
llhttp_get_error_pos: [Function: 30],
llhttp_errno_name: [Function: 31],
llhttp_method_name: [Function: 32],
llhttp_status_name: [Function: 33],
llhttp_set_lenient_headers: [Function: 34],
llhttp_set_lenient_chunked_length: [Function: 35],
llhttp_set_lenient_keep_alive: [Function: 36],
llhttp_set_lenient_transfer_encoding: [Function: 37],
llhttp_message_needs_eof: [Function: 63]
},
ptr: 141936,
client: Client {
_events: [Object: null prototype],
_eventsCount: 4,
_maxListeners: undefined,
[Symbol(kCapture)]: false,
[Symbol(destroyed)]: false,
[Symbol(onDestroyed)]: null,
[Symbol(closed)]: false,
[Symbol(onClosed)]: [],
[Symbol(dispatch interceptors)]: [Array],
[Symbol(url)]: [URL],
[Symbol(connector)]: [Function: connect],
[Symbol(socket)]: [Circular *1],
[Symbol(pipelining)]: 1,
[Symbol(max headers size)]: 16384,
[Symbol(default keep alive timeout)]: 4000,
[Symbol(max keep alive timeout)]: 600000,
[Symbol(keep alive timeout threshold)]: 1000,
[Symbol(keep alive timeout)]: 4000,
[Symbol(server name)]: null,
[Symbol(local address)]: null,
[Symbol(resuming)]: 0,
[Symbol(need drain)]: 2,
[Symbol(host header)]: 'host: localhost:3000\r\n',
[Symbol(body timeout)]: 300000,
[Symbol(headers timeout)]: 300000,
[Symbol(strict content length)]: true,
[Symbol(maxRedirections)]: undefined,
[Symbol(maxRequestsPerClient)]: undefined,
[Symbol(kClosedResolve)]: null,
[Symbol(max response size)]: -1,
[Symbol(queue)]: [Array],
[Symbol(running index)]: 0,
[Symbol(pending index)]: 1,
[Symbol(Intercepted Dispatch)]: [Function: Intercept],
[Symbol(connecting)]: false,
[Symbol(needDrain)]: true
},
socket: [Circular *1],
timeout: Timeout {
callback: [Function: onParserTimeout],
delay: 300000,
opaque: [Circular *2],
state: 1685997171039
},
timeoutValue: 300000,
timeoutType: 2,
statusCode: 200,
statusText: 'OK',
upgrade: false,
headers: [],
headersSize: 0,
headersMaxSize: 16384,
shouldKeepAlive: true,
paused: true,
resume: [Function: bound resume],
bytesRead: 73102,
keepAlive: 'timeout=5',
contentLength: '73102',
connection: 'keep-alive',
maxResponseSize: -1
},
[Symbol(client)]: Client {
_events: [Object: null prototype] {
drain: [Function: onDrain],
connect: [Function (anonymous)],
disconnect: [Function (anonymous)],
connectionError: [Function (anonymous)]
},
_eventsCount: 4,
_maxListeners: undefined,
[Symbol(kCapture)]: false,
[Symbol(destroyed)]: false,
[Symbol(onDestroyed)]: null,
[Symbol(closed)]: false,
[Symbol(onClosed)]: [],
[Symbol(dispatch interceptors)]: [ [Function (anonymous)] ],
[Symbol(url)]: URL {
href: 'http://localhost:3000/',
origin: 'http://localhost:3000',
protocol: 'http:',
username: '',
password: '',
host: 'localhost:3000',
hostname: 'localhost',
port: '3000',
pathname: '/',
search: '',
searchParams: URLSearchParams {},
hash: ''
},
[Symbol(connector)]: [Function: connect],
[Symbol(socket)]: [Circular *1],
[Symbol(pipelining)]: 1,
[Symbol(max headers size)]: 16384,
[Symbol(default keep alive timeout)]: 4000,
[Symbol(max keep alive timeout)]: 600000,
[Symbol(keep alive timeout threshold)]: 1000,
[Symbol(keep alive timeout)]: 4000,
[Symbol(server name)]: null,
[Symbol(local address)]: null,
[Symbol(resuming)]: 0,
[Symbol(need drain)]: 2,
[Symbol(host header)]: 'host: localhost:3000\r\n',
[Symbol(body timeout)]: 300000,
[Symbol(headers timeout)]: 300000,
[Symbol(strict content length)]: true,
[Symbol(maxRedirections)]: undefined,
[Symbol(maxRequestsPerClient)]: undefined,
[Symbol(kClosedResolve)]: null,
[Symbol(max response size)]: -1,
[Symbol(queue)]: [ [Request] ],
[Symbol(running index)]: 0,
[Symbol(pending index)]: 1,
[Symbol(Intercepted Dispatch)]: [Function: Intercept],
[Symbol(connecting)]: false,
[Symbol(needDrain)]: true
},
[Symbol(socket request counter)]: 0,
[Symbol(maxRequestsPerClient)]: undefined
} Hope this helps you debug this issue further. |
It looks like it's throwing due to |
I've tried setting options const { statusCode, headers } = await request(url.loc, {
signal: AbortSignal.timeout(10000),
throwOnError: true,
pipelining: 0
}); |
Shouldn't this be changed? Lines 989 to 993 in a3e0fdc
To: - if (parser.statusCode && !parser.shouldKeepAlive) {
+ if (parser.statusCode || !parser.shouldKeepAlive) {
// We treat all incoming data so far as a valid response.
parser.onMessageComplete()
return
} |
Additional findings:
|
The fix is to call This definitely seems like a major anti-pattern @mcollina @ronag. We don't explicitly state anywhere in the
|
I dont think this issue should be closed. @mcollina |
This issue has been closed since 3 years ago; please open a new one with a description and an |
… within the timeout of the last one - nodejs/undici#583
I'm still facing the issue in 2024. For anyone pulling their hair over this, this issue is not at all encountered with the bun runtime, give it a shot. |
Any update on this? I'm consuming the body with |
I have managed to fix this and other socket errors in my applications by limiting the nuber of connections NodeJS is allowed to open to the server. I observed that the node process was opening too many connections to the server, that is, using too many local ports of the host (16000+ in my case) and eventually these connections would end abruptly and cause the error. The number of connections can be limited via setting the
50 might not be an ideal number for you and you might still face the issue or your application might slow down because the process has lesser number of connections. You need to trial and error and find a number that works for you. 100 worked well for me when I did over 2 million async API calls for testing the limits. You can monitor the number of ports used by your node process on unix based systems via the following command
Bun used around 400-500 ports and was faster than NodeJS. I've tested using I haven't dug into whether the OS limits the number of connections, runs out of them or NodeJS is unable to handle them If this doesn't fix the issue for you and you want to dig in further, a packet capture can be helpful. I did a pcap and analyzed the packets in Wireshark. You'd want to look for the flow, source, destination, origin of the Also, if the server you're connecting to has rate limits, give a look at what it does to new connection requests and exising connections once the limits are hit Overall, this issue is now fixed for me and for all of the people I've recommended the above mentioned fix. |
The bug can popup when the disk is full also |
@aleluff This may be one of the cause as well. I had plenty of disk space available during working on this. |
Upon connecting to a proxy with user:pass it's all good, but when I try to make a request to an proxy which is IP authenticated, I get 'SocketError: other side closed'.
I'm not sending the proxy-authorization header as it's not needed.
Blanked the proxy ip and port below.
The text was updated successfully, but these errors were encountered: