This error occurs when attempting to read data from a Node.js stream that is not in a readable state, has already been consumed, or was never properly initialized as readable.
In Node.js, streams are abstract interfaces for working with streaming data. A readable stream represents a source from which data can be consumed sequentially, such as file reads, HTTP requests, or stdin. The "stream not readable" error indicates that code attempted to perform a read operation on a stream object that is not in a readable state. This can happen for several reasons: the stream may have been created as writable-only (like fs.WriteStream), the stream may have already been fully consumed and ended, or the stream's readable property may have been explicitly set to false. Some libraries and frameworks also mark streams as non-readable when internal failures occur during initialization or data generation. A particularly common scenario involves middleware in frameworks like Express, where multiple handlers may attempt to consume the same request body stream. Since streams can typically only be read once, the second handler encounters a non-readable stream.
Check if you're working with the correct type of stream and that it's in a readable state:
const stream = getYourStream();
// Check if stream is readable
console.log('Is readable:', stream.readable);
console.log('Is destroyed:', stream.destroyed);
console.log('Read method exists:', typeof stream.read === 'function');
// For HTTP requests, check if body was already consumed
if (stream.bodyUsed !== undefined) {
console.log('Body already used:', stream.bodyUsed);
}If stream.readable is false or the stream has been destroyed, you cannot read from it.
If you need to read stream data multiple times, buffer it on first read:
const getRawBody = require('raw-body');
async function bufferStream(req) {
// Store buffered body for reuse
if (!req.rawBody) {
req.rawBody = await getRawBody(req, {
length: req.headers['content-length'],
limit: '1mb',
encoding: 'utf-8'
});
}
return req.rawBody;
}
// Use in Express middleware
app.use(async (req, res, next) => {
await bufferStream(req);
next();
});This allows multiple handlers to access the same data without consuming the stream multiple times.
Replace manual pipe() calls with the pipeline() utility for automatic error handling:
const { pipeline } = require('stream');
const fs = require('fs');
// Instead of: readable.pipe(writable)
// Use:
pipeline(
fs.createReadStream('input.txt'),
transformStream,
fs.createWriteStream('output.txt'),
(err) => {
if (err) {
console.error('Pipeline failed:', err);
} else {
console.log('Pipeline succeeded');
}
}
);This ensures proper cleanup and error propagation across the entire pipeline.
Ensure body-parsing middleware runs before any handlers that consume the stream:
const express = require('express');
const app = express();
// Body parser MUST come first
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Your handlers come after
app.post('/api/data', (req, res) => {
// req.body is now available and stream was properly consumed
console.log(req.body);
res.json({ success: true });
});Incorrect ordering can cause subsequent handlers to encounter a non-readable stream.
When implementing custom readable streams, ensure proper initialization:
const { Readable } = require('stream');
class MyReadable extends Readable {
constructor(options) {
// IMPORTANT: Call super() to initialize readable state
super(options);
this.data = ['chunk1', 'chunk2', 'chunk3'];
}
_read() {
// Push data or null to signal end
const chunk = this.data.shift();
this.push(chunk || null);
}
}
const stream = new MyReadable();
stream.on('data', (chunk) => {
console.log('Received:', chunk.toString());
});Always call super() and implement the _read() method.
Always handle stream errors to catch issues early:
const stream = getYourStream();
stream.on('error', (err) => {
console.error('Stream error:', err.message);
// Handle cleanup or fallback logic
});
stream.on('end', () => {
console.log('Stream ended normally');
});
stream.on('close', () => {
console.log('Stream closed');
});Without error handlers, stream failures may manifest as "not readable" errors.
Stream Modes and States
Node.js streams operate in different modes that affect readability:
- Flowing mode: Data is read automatically and emitted via 'data' events
- Paused mode: Data must be explicitly read using stream.read()
Calling certain methods can switch modes and affect the stream's readable state. Once a stream emits the 'end' event, it cannot be made readable again.
Serverless and Lambda Considerations
In serverless environments like AWS Lambda with frameworks such as serverless-express, streams may be pre-processed or wrapped in ways that affect their readable state. Some frameworks buffer the entire request body before passing it to handlers, which can cause issues if your code expects a raw stream. Check your framework's documentation for how it handles request streams.
Memory and Backpressure
When working with streams, be mindful of backpressure—the situation where the destination cannot consume data as fast as the source produces it. Using pipeline() instead of pipe() provides better backpressure handling. If you must buffer streams for multiple reads, set appropriate size limits to prevent memory exhaustion.
Debugging Stream State
Use the stream.readableFlowing property to check the current mode:
- null: No consumption mechanism attached
- true: Flowing mode
- false: Paused mode
The stream.readableLength property shows how many bytes are queued in the internal buffer.
Error: Listener already called (once event already fired)
EventEmitter listener already called with once()
Error: EACCES: permission denied, open '/root/file.txt'
EACCES: permission denied
Error: Invalid encoding specified (stream encoding not supported)
How to fix Invalid encoding error in Node.js readable streams
Error: EINVAL: invalid argument, open
EINVAL: invalid argument, open
TypeError: readableLength must be a positive integer (stream config)
TypeError: readableLength must be a positive integer in Node.js streams