Invalid state: Controller is already closed
See original GitHub issueBug Description
When running my tests with undici v5.8.0 I am getting the traceback:
node:internal/errors:466
ErrorCaptureStackTrace(err);
^
TypeError: Invalid state: Controller is already closed
at new NodeError (node:internal/errors:377:5)
at ReadableStreamDefaultController.enqueue (node:internal/webstreams/readablestream:992:13)
at Fetch.fetchParams.controller.resume (/Users/fz/projects/centrifugal/centrifuge-js/node_modules/undici/lib/fetch/index.js:1864:41)
at processTicksAndRejections (node:internal/process/task_queues:95:5) {
code: 'ERR_INVALID_STATE'
I did some research if this can be helpful:
In my case the code in undici is getting exception in calling await fetchParams.controller.next()
in lib/fetch/index.js
, so catch branch works:
try {
const { done, value } = await fetchParams.controller.next()
if (isAborted(fetchParams)) {
break
}
bytes = done ? undefined : value
} catch (err) {
if (fetchParams.controller.ended && !timingInfo.encodedBodySize) {
// zlib doesn't like empty streams.
bytes = undefined
} else {
bytes = err
}
}
I added some console logging:
} catch (err) {
console.log(err); // DOMException [AbortError]: The operation was aborted.
console.log(fetchParams.controller.ended); // undefined
console.log(timingInfo.encodedBodySize); // 136
console.log(fetchParams.controller.ended && !timingInfo.encodedBodySize); // undefined
if (fetchParams.controller.ended && !timingInfo.encodedBodySize) {
// zlib doesn't like empty streams.
bytes = undefined
} else {
console.log("bytes is err"); // bytes is err
bytes = err
console.log(bytes instanceof Error); // false
console.log(typeof bytes); // object
}
}
The detailed exception is:
DOMException [AbortError]: The operation was aborted.
at new DOMException (node:internal/per_context/domexception:51:5)
at Fetch.abort (/Users/fz/projects/centrifugal/centrifuge-js/node_modules/undici/lib/fetch/index.js:89:20)
at AbortSignal.requestObject.signal.addEventListener.once (/Users/fz/projects/centrifugal/centrifuge-js/node_modules/undici/lib/fetch/index.js:165:20)
at AbortSignal.[nodejs.internal.kHybridDispatch] (node:internal/event_target:639:20)
at AbortSignal.dispatchEvent (node:internal/event_target:581:26)
at abortSignal (node:internal/abort_controller:291:10)
at AbortController.abort (node:internal/abort_controller:321:5)
at AbortSignal.abort (/Users/fz/projects/centrifugal/centrifuge-js/node_modules/undici/lib/fetch/request.js:372:32)
at AbortSignal.[nodejs.internal.kHybridDispatch] (node:internal/event_target:639:20)
at AbortSignal.dispatchEvent (node:internal/event_target:581:26)
So I suppose fetchParams.controller.controller.enqueue(new Uint8Array(bytes))
is called even if the stream was aborted.
Reproducible By
Create a new Node project with npm init
Add jest:
npm install --save-dev jest
Add test file index.test.js
:
test('test exception', async () => {
const d = new DOMException('test')
expect(d).toBeInstanceOf(Error)
expect(d instanceof Error).toBeTruthy()
})
Update package.json
to have:
{
"scripts": {
"test": "jest"
}
}
Run npm test
Expected Behavior
DOMException in Jest env does not extend Error, so stream aborting logic in https://github.com/nodejs/undici/blob/26f60b7b6e612bb831133d7f85914963d1955011/lib/fetch/index.js#L1857 does not work.
Environment
Node v18.2.0
Running tests with jest
Additional context
This reproduces starting from undici v5.6.0
Issue Analytics
- State:
- Created a year ago
- Comments:10 (5 by maintainers)
Jest has had an issue with
instanceof Error
for over half a decade now, this will most likely need to be fixed here. I’ll work on this tomorrow.Many thanks for helping with this, I tried to run tests with undici from the latest commit and it worked fine.