Koa: How to handle ECONNRESET and EPIPE on streaming?

Created on 27 Oct 2017  路  6Comments  路  Source: koajs/koa

Consider this example

const fs = require('fs');
const Koa = require('koa');

const app = new Koa();

app.use(async (ctx) => {
  ctx.body = fs.createReadStream('really-large-file');
});

app.listen(4000);

If user aborts request I'm getting either

  Error: read ECONNRESET
      at _errnoException (util.js:1024:11)
      at TCP.onread (net.js:618:25)

or

  Error: write EPIPE
      at _errnoException (util.js:1024:11)
      at WriteWrap.afterWrite [as oncomplete] (net.js:870:14)

What is the proper way to handle this type of errors?

P.S. I have no errors after request aborts with express

const fs = require('fs');
const express = require('express');

const app = express();

app.get('/', (req, res) => {
  fs.createReadStream('really-large-file').pipe(res);
});

app.listen(4000);

P.P.S. I've tried

app.use(async (ctx) => {
  fs.createReadStream('really-large-file').pipe(ctx.res);
  ctx.respond = false;
});

But it had no effect.

question

Most helpful comment

I know this is an old issue but in case someone finds it and is unable to get things to work properly (koa-onerror did not work for me), here's how I got this to work (koa 2.7.0).
Looking at the onerror function here: https://github.com/koajs/koa/blob/8b4e2cd3bc6e165a0ea544686346cd79e437bc28/lib/context.js#L121 and here: https://github.com/koajs/koa/blob/8b4e2cd3bc6e165a0ea544686346cd79e437bc28/lib/context.js#L123-L128 once the headers are sent, nothing is done. But the error is emitted as an app-level error.
So I created a handler for the app-level error event:

// Catch and log Koa app-level errors
const app = new Koa()
app.on('error', (error) => {
  if (error.code === 'EPIPE') {
    logger.warn('Koa app-level EPIPE error.', { error })
  } else {
    logger.error('Koa app-level error', { error })
  }
})

And now I'm no longer seeing the Error: write EPIPE messages 馃槉

All 6 comments

try koa-onerror to catch this error and handle it manually?

depends on how you want to handle the error. once the headers and the stream is already sent, there's not much you can do.

I'm experiencing the same issue using webpackHotMiddleware with ssr. Every time I refresh the page in chrome, the error appears:

Error: read ECONNRESET
      at _errnoException (util.js:1003:13)
      at TCP.onread (net.js:623:25)

in the server log.
As described in this thread, a close is not done correctly : https://github.com/websockets/ws/issues/1256
This thread deals with websocket, but we use event-stream here.

Is there a better way to handle this problem than just hiding the error with koa-onerror ?

Ok just found out resolving this problem in my case is impossible as event-stream does not communicate data to the server. So the server will never know when an user refresh its tab. We have to use a websocket communication to handle this.

I discovered koa-webpack with https://github.com/webpack-contrib/webpack-hot-client which implements a websocket approch and should be better than using koa-error. I will try that ;)

@GuillaumeCisco just thought I would mention: I wrote webpack-hot-client, and was researching the same ECONNRESET error in a separate project. your comment reminded me that I've already solved this problem in the past. Cheers.

I know this is an old issue but in case someone finds it and is unable to get things to work properly (koa-onerror did not work for me), here's how I got this to work (koa 2.7.0).
Looking at the onerror function here: https://github.com/koajs/koa/blob/8b4e2cd3bc6e165a0ea544686346cd79e437bc28/lib/context.js#L121 and here: https://github.com/koajs/koa/blob/8b4e2cd3bc6e165a0ea544686346cd79e437bc28/lib/context.js#L123-L128 once the headers are sent, nothing is done. But the error is emitted as an app-level error.
So I created a handler for the app-level error event:

// Catch and log Koa app-level errors
const app = new Koa()
app.on('error', (error) => {
  if (error.code === 'EPIPE') {
    logger.warn('Koa app-level EPIPE error.', { error })
  } else {
    logger.error('Koa app-level error', { error })
  }
})

And now I'm no longer seeing the Error: write EPIPE messages 馃槉

Was this page helpful?
0 / 5 - 0 ratings