remix icon indicating copy to clipboard operation
remix copied to clipboard

`FetchError: request to http://0.0.0.0:8000/graphql failed, reason: socket hang up`

Open IgnisDa opened this issue 2 years ago • 24 comments

What version of Remix are you using?

1.7.3

Steps to Reproduce

I have a graphql server. Making a single request to it in loader or action works fine. But if I have multiple requests:

await graphqlSdk().getStuff();
await graphqlSdk().getStuff();

it fails with the following error:

FetchError: request to http://0.0.0.0:8000/graphql failed, reason: socket hang up
    at ClientRequest.<anonymous> (/workspace/node_modules/.pnpm/@[email protected]/node_modules/@remix-run/web-fetch/src/fetch.js:111:11)
    at ClientRequest.emit (node:events:513:28)
    at Socket.socketOnEnd (node:_http_client:512:9)
    at Socket.emit (node:events:525:35)
    at endReadableNT (node:internal/streams/readable:1359:12)
    at processTicksAndRejections (node:internal/process/task_queues:82:21) {
  type: 'system',
  errno: 'ECONNRESET',
  code: 'ECONNRESET',
  erroredSysCall: undefined
}

Expected Behavior

The requests should succeed and my backend should receive 2 requests.

Actual Behavior

The first request succeeds but the second one does not.

IgnisDa avatar Oct 25 '22 08:10 IgnisDa

Update: it works fine if I use axios to make the requests.

IgnisDa avatar Oct 25 '22 11:10 IgnisDa

@IgnisDa could you provide a reproduction somewhere? Might be a problem with our web-fetch package

machour avatar Oct 25 '22 12:10 machour

@machour I am not able to reproduce it anywhere else. Can you give instructions on how to debug the web-fetch package? When I try to add a console.log in the file (that is shown in the error message above), I do not get any output.

IgnisDa avatar Oct 25 '22 14:10 IgnisDa

@IgnisDa try to create a repo with a simple Remix app reproducing the error, that way it would be possible to try it and debug it

sergiodxa avatar Oct 25 '22 15:10 sergiodxa

@sergiodxa As I said before, I am not able to reproduce it in a simple repository.

The error is occurring in this repository: https://github.com/IgnisDa/codefarem/tree/remix-issue

Could you take a look at the package.json if there are any dependencies that might change the behavior of the web-fetch package?

IgnisDa avatar Oct 25 '22 15:10 IgnisDa

I have the same error right now using fly in production, works fine in development

zifahm avatar Nov 07 '22 12:11 zifahm

can confirm changing from fetch to axios fixes the issue.

I'm quite confused why this would be a problem

zifahm avatar Nov 07 '22 14:11 zifahm

Having the same issue here. Will try to put together a minimal example. At the moment it seems like the issue is with web-fetch as simple node:http.request works fine.

richardbann avatar Nov 14 '22 19:11 richardbann

Manually setting the http.request option agent to false (in web-fetch) resolves this issue. So it has to do someting with the socket pool... (https://github.com/remix-run/web-std-io/blob/f715b354c8c5b8edc550c5442dec5712705e25e7/packages/fetch/src/request.js#L326)

richardbann avatar Nov 14 '22 22:11 richardbann

pinging @jacob-ebey since he worked on web-fetch

machour avatar Nov 15 '22 06:11 machour

Ok, this is probably a node 19 thing (https://github.com/nodejs/node/pull/43522). @IgnisDa , @zifahm , can you confirm you are using >= node 19? The default http agent now uses KeepAlive by default and it is not playing nicely with the manually set connection: close header. (https://github.com/remix-run/web-std-io/blob/f715b354c8c5b8edc550c5442dec5712705e25e7/packages/fetch/src/request.js#L302). To verify you can set KeepAlive in the fetch call:

resp = await fetch("http://myserver.test", {
  headers: { connection: "keep-alive" },
});

Could you please check @IgnisDa , @zifahm ? @jacob-ebey , please let me know if I should further investigate.

richardbann avatar Nov 15 '22 10:11 richardbann

@richardbann yup is using ENV NODE_VERSION=19.1.0

zifahm avatar Nov 15 '22 11:11 zifahm

hmm was using node:current in the docker container. now switched to node:lts-slim

zifahm avatar Nov 15 '22 11:11 zifahm

Can confirm headers: { connection: "keep-alive" } fixes it.

IgnisDa avatar Nov 15 '22 14:11 IgnisDa

Same here - I ran across the same FetchError triggered in the web-fetch package, though adding { connection: "keep-alive" } to my headers object fixed the issue. :+1:

eewang avatar Dec 21 '22 19:12 eewang

Ran into this after upgrading our remix project to node 20 as well. Can also confirm manually setting the connection header resolved the issue for us. The error triggered when we made multiple requests to the same API server in a single loader.

Jarrku avatar Sep 19 '23 14:09 Jarrku

I've got the same kind of problem with a node 21 project, remix 2.5.1. The 'connection' workaround seems to work.

gaetan-altech avatar Feb 05 '24 16:02 gaetan-altech

Same here - I ran across the same FetchError triggered in the web-fetch package, though adding { connection: "keep-alive" } to my headers object fixed the issue. 👍

Thanks, this one was driving me crazy.

hunt3r avatar Feb 13 '24 16:02 hunt3r

Are there any leads on solving the root of this issue? I'm using a 3rd party API where I can't add additional headers to fix this issue.

JesseFarebro avatar Apr 02 '24 00:04 JesseFarebro

@JesseFarebro The headers need to be set on your side when making the http request. Why can't you set the header?

IgnisDa avatar Apr 02 '24 00:04 IgnisDa

@IgnisDa I'm using a library that ends up calling fetch down the call stack. There is no options to pass through headers to fetch. The path of least resistance is probably to just wholesale copy some of their code for the time being.

JesseFarebro avatar Apr 02 '24 00:04 JesseFarebro

Same problem here

  • Im making 2 successive (2x await) http calls to an external api: I get socket hang up
  • I send them in parallele using promise.all : it works
  • 2 successive calls using headers: { connection: "keep-alive" }: it works

goldo avatar Jun 13 '24 12:06 goldo

Same issue with Node.js 21 and @neondatabase/serverless. Had to switch to postgres since I could not modify the headers for the same reason as @JesseFarebro's.

rojvv avatar Jun 13 '24 21:06 rojvv

@roj1512, there's an override for the fetch function in @neondatabase/serverless that lets you set the connection header.

import { neon, neonConfig } from "@neondatabase/serverless"
neonConfig.fetchFunction = (url: Parameters<typeof fetch>[0], options: Parameters<typeof fetch>[1]) => {
    options = options ?? {}
    options.headers = {
        ...(options.headers ?? {}),
        "connection": "keep-alive",
    }
    options.priority = "high"
    return fetch(url, options)
}
const sql = neon(`${process.env.DATABASE_URL_POOLED}`)

HeathHopkins avatar Jul 07 '24 04:07 HeathHopkins