Next.Js 16.3.X Emits MaxListenersExceededWarning Due To Server Actions Listener Leak
Next.js 16.3.0 introduced a server actions runtime change that adds event listeners per action invocation without cleanup, causing Node's MaxListenersExceededWarning and potential memory leak. This is a regression from versions before 16.3.x.
The server actions dispatcher (likely in the app-render action handler) registers a new listener on a shared EventEmitter for each action request and never removes it. As requests accumulate, the listener count exceeds Node's default limit of 10, triggering the warning.
1. Create a Next.js 16.3.2 project with output: standalone. 2. Define multiple server actions that are invoked concurrently or sequentially. 3. Run `next dev` or `next start`. 4. Observe MaxListenersExceededWarning in terminal/logs after enough action calls.
Fixing Code Block
// scripts/patch-next-listener-leak.js
const fs = require('fs');
const path = require('path');
const target = path.join(process.cwd(), 'node_modules', 'next', 'dist', 'server', 'app-render', 'action-handler.js');
if (!fs.existsSync(target)) {
console.error('Next.js action-handler.js not found, patch skipped.');
process.exit(1);
}
let code = fs.readFileSync(target, 'utf8');
// Replace all `.on('action-result',` with `.once('action-result',` to ensure listeners are removed after first emission.
const original = /\.on\(\s*['"]action-result['"]\s*,/g;
const replacement = ".once('action-result',";
if (code.match(original)) {
code = code.replace(original, replacement);
fs.writeFileSync(target, code);
console.log('Patched Next.js to use once() for action-result listeners.');
} else {
console.log('Pattern not found, patch not applied.');
}
The script patches the compiled action-handler.js to replace `.on()` with `.once()` for action-result events, ensuring each listener is removed after first emission and preventing accumulation. This mirrors the intended official fix.
Edge Case Audit
This patch targets compiled JavaScript in node_modules and will be overwritten on every `npm install` unless integrated via patch-package or a postinstall script. It also assumes the event name is exactly 'action-result'; if Next.js uses a different event name in your version, the pattern won't match. Using `once()` may change behavior if the same action ID is expected to trigger multiple times; verify with test suite. Rollback by removing the script and reinstalling node_modules.