This warning indicates that more than the default 10 listeners have been added to an EventEmitter without being removed, potentially causing memory leaks. Node.js warns you to either remove unused listeners, use emitter.setMaxListeners() to increase the limit, or refactor to avoid accumulating listeners.
Node.js EventEmitter instances have a safety limit on the number of listeners that can be attached to a single event. By default, this limit is 10 listeners per event. When you add more listeners than this limit, Node.js emits the MaxListenersExceededWarning to alert you of a potential memory leak. This warning suggests that listeners are being added without corresponding removal, which can cause memory to grow unbounded over time. The warning is a best-practice check—your code may still function correctly, but it's a sign that listener management should be reviewed. The warning often appears when making repeated HTTP requests with custom agents, creating many database connections, or subscribing to socket/stream events without proper cleanup.
The warning message will tell you which event name and how many listeners were added. Look for patterns like:
(node:12345) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 connection listeners added.Note the event name ('connection' in this example) and the listener count (11). Run with the trace-warnings flag for more details:
node --trace-warnings app.jsSave references to your listener functions and remove them after use:
const server = require('http').createServer();
const onConnection = (socket) => {
console.log('Client connected');
};
// Add listener
server.on('connection', onConnection);
// Remove listener when no longer needed
server.removeListener('connection', onConnection);
// Or remove all listeners:
server.removeAllListeners('connection');Always remove listeners that are only needed temporarily. For one-time events, use emitter.once() instead of emitter.on().
For event handlers that should only fire once, use .once() instead of .on(). The listener is automatically removed after firing:
const socket = require('net').createConnection();
// Good: listener automatically removed after first 'connect' event
socket.once('connect', () => {
console.log('Connected once');
});
// Not ideal: listener persists after first event
socket.on('connect', () => {
console.log('Connected');
});This prevents accidental listener accumulation.
If you have reviewed your code and verified that listeners are being added and removed correctly, you can increase the listener limit using setMaxListeners():
const emitter = new require('events').EventEmitter();
// Increase limit to 20 listeners
emitter.setMaxListeners(20);
// Or disable the limit entirely (use with caution)
emitter.setMaxListeners(0); // 0 = unlimitedYou can also set the default limit for all new EventEmitter instances:
require('events').EventEmitter.defaultMaxListeners = 20;Important: Only increase the limit after confirming listeners are being properly managed. Blindly increasing the limit masks underlying memory leak issues.
Check for these common patterns that cause listener accumulation:
Pattern 1: Registering listeners in loops or repeated function calls
// Bad: listener added every time function is called
function fetchData() {
const request = http.get(url);
request.on('response', handleResponse); // Added repeatedly!
}
for (let i = 0; i < 1000; i++) {
fetchData(); // 1000 listeners added
}
// Good: use once() or handle cleanup
function fetchData() {
const request = http.get(url);
request.once('response', handleResponse); // Auto-removed after first call
}Pattern 2: Custom HTTP agents with keepAlive
// Bad: each request adds listeners to the same agent
const agent = new http.Agent({ keepAlive: true });
for (let i = 0; i < 1000; i++) {
http.get(url, { agent }, callback);
}
// Good: reuse the same agent with setMaxListeners
const agent = new http.Agent({ keepAlive: true });
agent.setMaxListeners(100);
for (let i = 0; i < 1000; i++) {
http.get(url, { agent }, callback);
}Pattern 3: Stream event listeners
// Bad: listeners not removed
const fs = require('fs');
function readFile() {
const stream = fs.createReadStream('file.txt');
stream.on('data', handleData); // Added repeatedly
}
// Good: use once() or proper cleanup
function readFile() {
const stream = fs.createReadStream('file.txt');
stream.once('data', handleData);
stream.once('end', () => stream.destroy());
}Use Node.js EventEmitter methods to inspect listener state:
const emitter = new require('events').EventEmitter();
// Add some listeners
emitter.on('test', () => {});
emitter.on('test', () => {});
// Check current listener count
console.log(emitter.listenerCount('test')); // 2
// Check the maximum limit
console.log(emitter.getMaxListeners()); // 10 (default)
// Get all listeners for an event
console.log(emitter.listeners('test')); // Array of listener functions
// Monitor for listener changes
emitter.on('newListener', (event, func) => {
console.log(`Listener added to ${event} event`);
});
emitter.on('removeListener', (event, func) => {
console.log(`Listener removed from ${event} event`);
});Use these methods during development to track listener lifecycle and catch accumulation early.
The default limit of 10 listeners is intentionally low to catch potential memory leaks during development. In production, you may legitimately have more listeners for certain events (like database connection 'connect' events in a pool), so increasing the limit is acceptable after code review.
Node.js will not throw an error when the listener limit is exceeded—it only emits the warning and continues executing. This means buggy code that accumulates listeners will appear to work initially but will eventually consume all available memory.
When using HTTP/HTTPS with custom agents, the limit is often hit on the socket-level emitters (like TLSSocket) rather than the main server/client emitter. The warning may point to internal Node.js listeners, which is why inspecting your own code may not reveal the issue immediately—check for agent reuse and keepAlive settings.
For applications that legitimately create many connections (like connection pools or load balancers), consider using a separate EventEmitter per connection pool or increasing the limit selectively rather than globally, to preserve warnings for code paths where leaks are less expected.
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