undici icon indicating copy to clipboard operation
undici copied to clipboard

Uncaught TypeError: terminated

Open loynoir opened this issue 3 years ago • 6 comments

Bug Description

Uncaught TypeError: terminated

Reproducible By

TEST_URL

  • may be status 401, other status is not tested.
  • MUST have not-empty-body, so things like https://httpbin.org/status/401 will not work
  • In this reproduce case, total body only have one chunk.
> var{fetch}=await import('undici');
> r=await fetch(TEST_URL);
Response
> rd=r.body.getReader();
ReadableStreamDefaultReader
> c0=await rd.read();
{ done: false, value: Uint8Array(141) }

Expected Behavior

Firefox

> c1=await rd.read();
{ done: true, value: undefined }

Logs & Screenshots

Node v18.10.0

> c1=await rd.read();
Uncaught TypeError: terminated
    at Fetch.onAborted (undici/lib/fetch/index.js:1874:49)
    at Fetch.emit (node:events:513:28)
    at Fetch.emit (node:domain:552:15)
    at Fetch.terminate (undici/lib/fetch/index.js:83:10)
    at Object.onError (undici/lib/fetch/index.js:2015:34)
    at Request.onError (undici/lib/core/request.js:265:27)
    at errorRequest (undici/lib/client.js:1722:13)
    at Socket.onSocketClose (undici/lib/client.js:985:5)
    at Socket.emit (node:events:513:28)
    at Socket.emit (node:domain:552:15) {
  [cause]: SocketError: closed
      at Socket.onSocketClose (undici/lib/client.js:967:31)
      at Socket.emit (node:events:513:28)
      at Socket.emit (node:domain:552:15)
      at TCP.<anonymous> (node:net:313:12)
      at TCP.callbackTrampoline (node:internal/async_hooks:130:17) {
    code: 'UND_ERR_SOCKET',
    socket: {
      localAddress: undefined,
      localPort: undefined,
      remoteAddress: undefined,
      remotePort: undefined,
      remoteFamily: undefined,
      timeout: undefined,
      bytesWritten: 168,
      bytesRead: 334
    }
  }
}

Environment

  • Firefox
  • Node v18.10.0
  • undici 5.11.0

Additional context

loynoir avatar Oct 06 '22 04:10 loynoir

Related https://github.com/nodejs/undici/issues/1490

loynoir avatar Oct 06 '22 04:10 loynoir

Can you also include a small server?

mcollina avatar Oct 06 '22 09:10 mcollina

undici Error

An real world example, I put undici in unit test, and it failed. Below is a curl log.

no Content-Length

< HTTP/1.0 401 Unauthorized
< Foo: foo
< Connection: close
< Bar: bar
<
{{body}}
* Closing connection 0

undici OK

The response I can reproduce in nodejs.

no Content-Length

< HTTP/1.1 401 Unauthorized
< Foo: foo
< Connection: close
< Bar: bar
< Transfer-Encoding: chunked
<
* Closing connection 0
{{body}}

Conclusion

Seems like root cause is one of below

  • HTTP/1.0. No idea how to reproduce that in node
  • Lack of Transfer-Encoding and Content-Length at the same time
  • Not sure why below curl log is different, maybe Transfer-Encoding?
{{body}}
* Closing connection 0

loynoir avatar Oct 09 '22 23:10 loynoir

Thanks for reporting. Undici is an HTTP/1.1 client and this issue is about HTTP/1.0 support. I do not think we have the bandwidth to work on this issue right now, but we'll be very happy if somebody would like to work on this.

mcollina avatar Oct 10 '22 05:10 mcollina

https://github.com/loynoir/reproduce-undici-1688

node.js

  ✔ fetch test: cgi with-content-length
  1) fetch test: cgi without-content-length

  1 passing (60ms)
  1 failing

  1) fetch test: cgi without-content-length:
     TypeError: terminated
      at Fetch.onAborted (node_modules/undici/lib/fetch/index.js:1874:49)
      at Fetch.emit (node:events:513:28)
      at Fetch.terminate (node_modules/undici/lib/fetch/index.js:83:10)
      at Object.onError (node_modules/undici/lib/fetch/index.js:2015:34)
      at Request.onError (node_modules/undici/lib/core/request.js:265:27)
      at errorRequest (node_modules/undici/lib/client.js:1722:13)
      at Socket.onSocketClose (node_modules/undici/lib/client.js:985:5)
      at Socket.emit (node:events:513:28)
      at TCP.<anonymous> (node:net:313:12)

browser

✔ fetch test: cgi with-content-length
✔ fetch test: cgi without-content-length

loynoir avatar Oct 10 '22 07:10 loynoir

First time experiencing this one as well, just today.

From my experience this happens when fetch response status code is different other than 200. It seems some status code like 302 and 307 does not like having response body so doing await response.json() results into TypeError: terminated. Status code 401 is fine to receive a body so it works. I would like to mention #426 to be a more reliable solution going forward so people could stop shooting themselves in the foot.

lnfel avatar Nov 03 '23 04:11 lnfel