(regression?) timeouts while reading a body no longer abort with a TimeoutError
Bug Description
I'm not sure when this changed, but undici no longer throws a TimeoutError when reading the body
Reproducible By
import { fetch as undiciFetch } from 'undici';
async function test(method) {
try {
const signal = AbortSignal.timeout(1000);
const res = await method('https://httpbin.org/drip?duration=2&numbytes=10&code=200&delay=0', {signal});
try {
await res.arrayBuffer();
} catch (error) {
console.log('body read timeout')
console.log(error instanceof DOMException);
console.log(error.code === 23);
console.log(error);
}
} catch (error) {
console.log('header read timeout')
console.log(error instanceof DOMException);
console.log(error.code === 23);
console.log(error);
}
}
await test(undiciFetch);
await test(fetch);
Expected Behavior
Both calls should abort with a TimeoutError
Logs & Screenshots
body read timeout
true
false
DOMException [AbortError]: The operation was aborted.
at new DOMException (node:internal/per_context/domexception:53:5)
at Fetch.abort (/home/sia/dev/platform/next-server/node_modules/undici/lib/fetch/index.js:108:15)
at requestObject.signal.addEventListener.once (/home/sia/dev/platform/next-server/node_modules/undici/lib/fetch/index.js:189:20)
at [nodejs.internal.kHybridDispatch] (node:internal/event_target:826:20)
at EventTarget.dispatchEvent (node:internal/event_target:761:26)
at abortSignal (node:internal/abort_controller:371:10)
at AbortController.abort (node:internal/abort_controller:393:5)
at EventTarget.abort (/home/sia/dev/platform/next-server/node_modules/undici/lib/fetch/request.js:368:16)
at [nodejs.internal.kHybridDispatch] (node:internal/event_target:826:20)
at EventTarget.dispatchEvent (node:internal/event_target:761:26)
body read timeout
true
true
DOMException [TimeoutError]: The operation was aborted due to timeout
at new DOMException (node:internal/per_context/domexception:53:5)
at Timeout._onTimeout (node:internal/abort_controller:130:9)
at listOnTimeout (node:internal/timers:573:17)
at process.processTimers (node:internal/timers:514:7)
Environment
node v20.12.2 undici 6.16.0
Additional context
Tested with latest main without success:
const { fetch: undiciFetch } = require('undici')
async function test (method) {
const signal = AbortSignal.timeout(1000)
const res = await method(
'https://httpbin.org/drip?duration=2&numbytes=10&code=200&delay=0',
{ signal }
)
await res.arrayBuffer()
}
test(undiciFetch).then(
() => {
console.log('undicifetch: done')
},
err => console.log('undicifetch:', err)
)
test(fetch).then(
() => {
console.log('fetch: done')
},
err => console.log('fetch:', err)
)
Outcome:
undicifetch: DOMException [TimeoutError]: The operation was aborted due to timeout
at new DOMException (node:internal/per_context/domexception:53:5)
at Timeout._onTimeout (node:internal/abort_controller:130:9)
at listOnTimeout (node:internal/timers:573:17)
at process.processTimers (node:internal/timers:514:7)
fetch: DOMException [TimeoutError]: The operation was aborted due to timeout
at new DOMException (node:internal/per_context/domexception:53:5)
at Timeout._onTimeout (node:internal/abort_controller:130:9)
at listOnTimeout (node:internal/timers:573:17)
at process.processTimers (node:internal/timers:514:7)
@metcoder95 what you posted would be the intended outcome. You're not logging if it was a header or body timeout. header timeouts appeared to throw a TimeoutError in my tests.
but today I can't replicate it any longer. Neither with undici 6.16.0 nor any later version...
According to the stacktrace the error is thrown here
at Fetch.abort (/home/sia/dev/platform/next-server/node_modules/undici/lib/fetch/index.js:108:15)
but there is no such location. The stacktrace is swallowing the web directory. it should've been
/home/sia/dev/platform/next-server/node_modules/undici/lib/web/fetch/index.js
It throws there when error is falsy. I'll try to figure out how that can happen
Can't replicate it anymore