undici icon indicating copy to clipboard operation
undici copied to clipboard

(regression?) timeouts while reading a body no longer abort with a TimeoutError

Open simhnna opened this issue 1 year ago • 2 comments

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

simhnna avatar May 23 '24 14:05 simhnna

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 avatar May 23 '24 18:05 metcoder95

@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

simhnna avatar May 24 '24 07:05 simhnna

Can't replicate it anymore

simhnna avatar Jul 29 '24 12:07 simhnna