axios icon indicating copy to clipboard operation
axios copied to clipboard

HTTP Keep-alive, "socket hang up" ECONNERR on a long-running second request

Open snarky-puppy opened this issue 2 years ago • 32 comments

Describe the bug

On keep-alive connections, if a timeout value is given to the first request but not on subsequent requests, the subsequent requests will eventually throw a "socket hang up" error.

To Reproduce

const http = require('http');
const axios = require('axios');

describe('socket hang up', () => {
    let server;
    beforeAll(done => {
        server = http.createServer(async (req, res) => {
            if (req.url === '/wait') {
                await new Promise(resolve => setTimeout(resolve, 5000));
            }
            res.end('ok');
        });
        server.listen(3000, done);
    });

    afterAll(done => {
        server.close(done);
    });

    it('will fail with "socket hang up"', async () => {
        const baseURL = `http://localhost:3000`;
        await axios.get('/1', {baseURL, timeout: 1000});
        await axios.get(`/wait`, {baseURL, timeout: 0});
    }, 15000);
});

Code snippet

No response

Expected behavior

  1. "socket hang up" is misleading because it indicates the server closed the connection (in this bug the opposite is true)
  2. One would not expect that a timeout would keep running after a request has completed. This is a (quite major IMO) footgun.

Axios Version

0.22.0 - 1.6.2

Adapter Version

HTTP

Browser

No response

Browser Version

No response

Node.js Version

20.9.0

OS

OSX 14

Additional Library Versions

No response

Additional context/Screenshots

tcpdump

snarky-puppy avatar Dec 04 '23 06:12 snarky-puppy

We're also affected by this bug.

avermeil avatar Dec 06 '23 13:12 avermeil

Cheers! I am affected with same bug, but can only reproduce it at Node 20.10, fallback to Node 18.18 works fine.

Avariya avatar Dec 08 '23 08:12 Avariya

The cause of this issue is the way follow-redirects implements timeout. It has problems when dealing with keep-alive connections. A simple fix is to remove the timeout event handler when the request finishes, but I'm not sure this will work for all use-cases, as that library is mostly geared towards earlier node versions.

snarky-puppy avatar Dec 17 '23 22:12 snarky-puppy

Same issue here. Is there any workaround except a dumb retry?

NaZaRKIN123 avatar Jan 24 '24 17:01 NaZaRKIN123

Same issue here. Is there any workaround except a dumb retry?

@NaZaRKIN123 Something like this would work:

axios.defaults.httpAgent = new Agent({ keepAlive: false });

snarky-puppy avatar Jan 25 '24 03:01 snarky-puppy

I can confirm that the workaround provided by @snarky-puppy worked for us 🙏

TkDodo avatar Jan 26 '24 15:01 TkDodo

Thanks for the detail investigation. The keepAlive is needed on my project in order to reduce latency In case we disable follow-redirects, would that be solved?

chanyk-joseph avatar May 08 '24 04:05 chanyk-joseph

+1

ricfio avatar Jun 19 '24 15:06 ricfio

+1

KyrieLii avatar Jul 02 '24 11:07 KyrieLii

+1

davidln777 avatar Jul 08 '24 16:07 davidln777

+1

dathacky avatar Jul 22 '24 06:07 dathacky

Cheers! I am affected with same bug, but can only reproduce it at Node 20.10, fallback to Node 18.18 works fine.

This is because of #6536. Short summary: Node.js changed its default Keep-Alive behavior after Node.js 18.

nikwen avatar Aug 11 '24 14:08 nikwen