Skip to content

ECONNRESET due to upstream timeout causes crash #79

@ImranR-TI

Description

@ImranR-TI

Environment

Node 22.14.0, httpxy 0.1.7

Reproduction

https://github.com/ImranR-TI/httpxy_econnreset_minimal

  1. Install HAProxy and use the haproxy.cfg provided.
  2. Run node proxy.js
  3. Install wscat and run: wscat -c http://localhost:80/socket

It eventually crashes with this error: error: Unexpected server response: 502

Proxy logs:

Proxy server listening on port 8000
node:events:496
      throw er; // Unhandled 'error' event
      ^

Error: read ECONNRESET
    at TCP.onStreamRead (node:internal/stream_base_commons:216:20)
Emitted 'error' event on Socket instance at:
    at emitErrorNT (node:internal/streams/destroy:170:8)
    at emitErrorCloseNT (node:internal/streams/destroy:129:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
  errno: -104,
  code: 'ECONNRESET',
  syscall: 'read'
}

Node.js v22.14.0

Describe the bug

I'm seeing the httpxy crash with ECONNRESET in a specific scenario (minimal reproducible example above).

Basically I have the following setup: [client] --> [HAProxy] --> [Node proxy] --> [backend]

  1. A backend socket server
  2. A Node proxy server powered by httpxy
    • This has some conditional logic which ensures that only specific requests are forwarded to the backend - the rest are simply ignored (no response). So clients are left waiting forever.
  3. A second proxy (HAProxy) in front of the Node proxy, that has some default request timeout value
    • This ensures that requests left waiting forever for some response (that will never come) do eventually have to break the connection.
    • I'm using HAProxy but I think anything similar would work here.

The bug I'm seeing has to do with this external timeout - it causes the Node proxy to crash with ECONNRESET. The error itself is not a problem, we would expect to see an error in this kind of situation. The problem is that the error crashes the entire process despite the presence of a proxy.on('error') listener.

I know this is a weird use case (my code should ideally respond to "ignored" requests with a 404 or something instead of completely ignoring them) but it does still expose what I think is a bug.

Minimal code to reproduce the bug is in the repo linked above.

Note backend.js has been omitted since it doesn't really matter in this case whether or not a backend exists - we never proxy the request anyways.

Thanks for this rewrite BTW, the old one had a bad memory leak (among other issues).

Additional context

No response

Logs

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions