How to handle stream errors?
Tags: node, javascript
Published: 2021-08-11 11:01:07

---
title: How to handle stream errors?
published: true
date: 2021-08-10 00:00:00 UTC
tags: node, javascript
canonical_url: https://www.mariokandut.com/how-to-handle-streams-errors-in-node-js/
---

Streams are a built-in feature in Node.js and represent asynchronous flow of data. Streams are also a way to handle reading and/or writing files. A Node.js stream can help process large files, larger than the free memory of your computer, since it processes the data in small chunks.

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#streams-in-nodejs)Streams in Node.js

This is the third article of a series about streams in Node.js. It explains how to handle errors in streams.

**Streams in Node.js**

- [What is a Stream in Node.js?](https://www.mariokandut.com/what-is-a-node-js-stream/)
- [Connect streams with the pipe method](https://www.mariokandut.com/how-to-connect-streams-with-pipe-in-node-js/)
- Handle stream errors (this article)
- Connect streams with the pipeline method (planned)

### [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#handling-stream-errors)Handling stream errors

Building robust Node.js applications requires dealing with errors in proper way. Have a look at the article series about Node.js errors for a refresher on errors - [Errors in Node.js](https://www.mariokandut.com/introduction-to-errors-in-node-js/).

The most important event emitted by a stream is the error event. If this error event is not handled, it can crash your application. Hence, errors have to be handled when working with streams.

### [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#error-event-handler)Error event handler

To handle error events attach an event handler directly on the stream.

Let's create a `PassThrough` stream and add event handlers.

Create a file.

```
touch streams-error-emit.js
```

Add code.

```
const { PassThrough } = require('stream');

const passThrough = new PassThrough();

passThrough.on('error', err => {
  console.error('passThrough encountered an error:', err);
});
process.stdin.on('error', err => {
  console.error('stdin encountered an error:', err);
});
process.stdout.on('error', err => {
  console.error('stdout encountered an error:', err);
});

process.stdin.pipe(passThrough).pipe(process.stdout);

passThrough.emit('error', new Error('Somewthing went wrong!'));
```

When you run the code with `node stream-error-emit.js` from the CLI the error will be first emitted from `PassThrough`, and then handled by it with throwing the error message `passThrough encountered an error: Error: Somewthing went wrong!`. Now try to remove the error handling for the `PassThrough` stream, just for fun. The example will crash with unhandled exception, exiting the program early and with a status code of 1.

Handling errors this way works and prevents your application from crashing. However, it can be unmanageable to attache these event handlers for every stream when working with the `pipe` method.

Handling errors with the `pipeline` method is much cleaner and manageable. The `callback` is called when the pipeline is fully done and can handle errors.

```
pipeline(
  source stream,
  transform or other streams,
  destination stream,
  (err) => {
      if (err) {
        console.error('Pipeline failed.', err);
      } else {
        console.log('Pipeline succeeded.');
      }
    }
);
```

### [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#finished)finished()

The `finished()` function gets triggered when a stream is no longer readable, writable or has experienced an error, or a premature close event. Handling errors with `finished()` is another option and was added in Node.js version 10. It takes a stream with options as first, and a callback as second argument - `stream.finished(stream[, options], callback)`-

```
const { finished } = require('stream');

const rs = fs.createReadStream('archive.tar');

finished(rs, err => {
  if (err) {
    console.error('Stream failed.', err);
  } else {
    console.log('Stream is done reading.');
  }
});
```

The `finished` function is especially useful in error handling scenarios, where a stream is destroyed prematurely (like an aborted HTTP request), and will not emit `end` or `finish`.

The `finished` API also provides a `promise` version:

```
const { finished } = require('stream/promises');

const rs = fs.createReadStream('archive.tar');

async function run() {
  await finished(rs);
  console.log('Stream is done reading.');
}

run().catch(console.error);
rs.resume(); // Drain the stream.
```

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#tldr)TL;DR

- Unhandled stream errors crash the application.
- One option to handle stream errors is to attach an event handler and listen to error events.
- Another option to handle errors is the `finished` function. It is especially useful in error handling scenarios, where `end` or `finished` are not emitted.
- The `pipeline` method provides an easier way to handle error events.

Thanks for reading and if you have any **questions** , use the **comment** function or **send me a message** **[@mariokandut](https://www.twitter.com/mariokandut)**.

If you want to know more about **[Node](https://www.mariokandut.com/tags/node)**, have a look at these [Node Tutorials](https://www.mariokandut.com/tags/node).

**References (and Big thanks):**

[HeyNode](https://heynode.com/tutorial/what-stream/),[Node.js - Streams](https://nodejs.org/api/stream.html#stream_stream),[MDN - Streams](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API)