This error occurs when you attempt to configure a Node.js stream with an invalid readableLength value. readableLength must be a positive integer (greater than 0) when specified. Invalid values like negative numbers, zero, strings, or non-integer values will trigger this TypeError.
The readableLength property in Node.js streams represents the number of bytes currently queued in the stream's internal buffer waiting to be read. While readableLength is typically a read-only property that tracks the current buffer state, if you're setting it as a configuration option during stream creation or in custom stream implementations, it must be a valid positive integer. When passed as a configuration parameter to stream constructors or custom Readable stream implementations, Node.js validates readableLength strictly: it must be a positive whole number (greater than 0, not zero). This is distinct from highWaterMark, which can be 0 or higher. If you pass an invalid value—such as a negative number, zero, a non-integer decimal, a string, null, or undefined—Node.js throws a TypeError to prevent misconfiguration of your stream's buffering behavior. This validation ensures that the stream's internal queue can properly track buffered data and prevent memory issues.
Check your stream creation code. readableLength is a read-only property, not typically a configuration option. If you're trying to configure stream buffering, use highWaterMark instead:
// WRONG: readableLength is not a configuration option
const stream = fs.createReadStream('file.txt', { readableLength: 1024 });
// CORRECT: Use highWaterMark to configure buffer threshold
const stream = fs.createReadStream('file.txt', { highWaterMark: 1024 });
// readableLength is used to check current buffer state
stream.on('readable', () => {
console.log('Current buffered bytes:', stream.readableLength);
});If implementing a custom Readable stream, verify you're not setting readableLength as a constructor option. It should be managed internally:
const { Readable } = require('stream');
// WRONG: readableLength is not a valid option in constructor
class CustomReadable extends Readable {
constructor(options) {
super(options);
// Don't set readableLength - it's read-only
}
}
// CORRECT: Use highWaterMark for configuration
class CustomReadable extends Readable {
constructor(options = {}) {
super({
highWaterMark: options.highWaterMark || 16384,
encoding: options.encoding,
objectMode: options.objectMode
});
this.dataSource = options.dataSource;
}
_read(size) {
// Read data from source
const data = this.dataSource.read(size);
if (data) {
this.push(data);
}
}
}
// Create instance
const readable = new CustomReadable({ highWaterMark: 2048 });
// Check readableLength (read-only property)
readable.on('data', (chunk) => {
console.log('Bytes buffered:', readable.readableLength);
});If you're passing a configuration object to stream constructors, remove any readableLength property. Use highWaterMark instead:
// WRONG: Configuration with readableLength
const streamOptions = {
encoding: 'utf8',
readableLength: 4096, // Invalid configuration
objectMode: false
};
const stream = fs.createReadStream('file.txt', streamOptions);
// CORRECT: Use highWaterMark for buffering control
const streamOptions = {
encoding: 'utf8',
highWaterMark: 4096, // Controls buffer threshold
objectMode: false
};
const stream = fs.createReadStream('file.txt', streamOptions);If reading configuration from environment variables or external sources, ensure numeric values are properly converted. Verify highWaterMark is used instead of readableLength:
// WRONG: String value and wrong property name
const config = {
readableLength: '4096', // String and invalid property
};
const stream = fs.createReadStream('file.txt', config);
// CORRECT: Parse to integer and use highWaterMark
const config = {
highWaterMark: parseInt(process.env.STREAM_BUFFER || '16384', 10),
};
const stream = fs.createReadStream('file.txt', config);
// CORRECT: Type-safe configuration
function validateStreamConfig(options) {
if (options.highWaterMark) {
const hwm = options.highWaterMark;
if (typeof hwm !== 'number' || !Number.isInteger(hwm) || hwm < 0) {
throw new TypeError('highWaterMark must be a non-negative integer');
}
}
// Never set readableLength in options
if (options.readableLength !== undefined) {
throw new TypeError('readableLength is read-only, use highWaterMark instead');
}
return options;
}
const validConfig = validateStreamConfig({
highWaterMark: 8192,
encoding: 'utf8'
});
const stream = fs.createReadStream('file.txt', validConfig);Use readableLength to inspect the stream's buffer state during operation, but never attempt to set it. This is the correct usage pattern:
const fs = require('fs');
const stream = fs.createReadStream('large-file.txt', { highWaterMark: 16384 });
// Monitor readableLength (read-only)
stream.on('readable', () => {
console.log('Bytes waiting to be read:', stream.readableLength);
// Read data
let chunk;
while ((chunk = stream.read()) !== null) {
console.log('Read', chunk.length, 'bytes');
console.log('Remaining buffered:', stream.readableLength);
}
});
// DO NOT attempt to set readableLength
// stream.readableLength = 1024; // This won't work and may cause issues
stream.on('end', () => {
console.log('Stream ended');
});
stream.on('error', (error) => {
console.error('Stream error:', error);
});If the error comes from a third-party library, check the library's documentation for correct stream options. Many libraries use highWaterMark, not readableLength:
// Example: axios with streams
import axios from 'axios';
import fs from 'fs';
// WRONG: Some libraries might accept stream options, but readableLength is invalid
const response = await axios({
method: 'get',
url: 'https://example.com/file.bin',
responseType: 'stream',
// Don't add readableLength here
});
// CORRECT: Configure stream options properly
const stream = fs.createReadStream('input.txt', {
highWaterMark: 32768, // Valid option
encoding: 'utf8'
});
// If using a custom stream wrapper, ensure it validates options
class StreamWrapper {
constructor(options = {}) {
const validOptions = {};
// Only set valid stream options
if (options.highWaterMark !== undefined) {
validOptions.highWaterMark = options.highWaterMark;
}
if (options.encoding) {
validOptions.encoding = options.encoding;
}
// Never copy readableLength to stream options
if (options.readableLength !== undefined) {
console.warn('readableLength is read-only, ignoring this option');
}
this.stream = fs.createReadStream(options.path, validOptions);
}
}Understanding readableLength vs. highWaterMark:
readableLength is always a read-only property that reflects the current number of bytes buffered in the stream's internal queue. highWaterMark is the configuration option that controls the threshold at which the stream pauses reading. These are different concepts: highWaterMark is set once during configuration, while readableLength changes dynamically as data flows through the stream.
Stream Buffering Mechanics:
When you call stream.read(), data is removed from the internal buffer and readableLength decreases accordingly. This is useful for monitoring backpressure conditions: if readableLength approaches highWaterMark, the stream will soon pause reading from its source to prevent memory exhaustion.
Custom Stream Implementations:
If implementing a custom Readable stream by extending the Readable class, manage the internal buffer through the push() method in your _read() implementation. The Node.js stream infrastructure automatically updates readableLength—you should never attempt to set it manually. Always configure highWaterMark in the constructor super() call if custom buffering is needed.
Backpressure Detection:
Use readableLength to detect backpressure conditions and implement adaptive buffering strategies:
const readable = fs.createReadStream('file.txt', { highWaterMark: 16384 });
const writable = fs.createWriteStream('output.txt');
readable.on('readable', () => {
let chunk;
while ((chunk = readable.read()) !== null) {
const continueWriting = writable.write(chunk);
// If buffer is growing (backpressure), pause reading
if (readable.readableLength > readable.readableHighWaterMark) {
readable.pause();
}
}
});
writable.on('drain', () => {
readable.resume();
});This pattern is automatically handled by pipe() and stream.pipeline(), which is why those are preferred over manual stream composition for most applications.
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
Error: setuid EPERM (operation not permitted, user change failed)
setuid EPERM: Operation not permitted when changing process user