FULL AI ANALYSIS

Node.js Express app showing unbounded memory growth traced to accumulating event listeners and timers

Generated Oct 3, 2026, 12:35:03 AM

Analysis summary

The pattern of accumulating EventEmitter listeners and uncleared timers indicates a resource lifecycle bug: either per-request objects are registering process-level listeners and never deregistering, or third-party modules create listeners/timers on every instantiation without cleanup. setInterval/setTimeout and EventEmitter leaks commonly arise from attaching listeners in request handlers or failing to call removeListener/clearInterval on error or connection close paths. The MaxListenersExceededWarning points to an emitter that is being reused but not cleaned up.

Possible causes

Uncleared setInterval/setTimeout timers created per request or per connection

95%

Attaching process- or module-scoped event listeners inside per-request code paths without removing them

90%

Third-party module that instantiates a global emitter per use and doesn't expose a cleanup API

85%

Callbacks/closures capturing large objects preventing GC (e.g., promise chains that never settle)

40%

Suggested fixes

1

Diagnostic step 1

Produce time-series heap snapshots and use heapdiff to identify retained object types and their retaining paths; automate snapshot capture under normal load and after a restart.

2

Diagnostic step 2

Search codebase for EventEmitter.on/addListener and setInterval/setTimeout calls inside request handlers or modules initialized per-request; refactor to attach listeners once at process start or ensure removal on request end (use emitter.removeListener or emitter.off and clearInterval).

3

Diagnostic step 3

Wrap third-party clients to a single shared instance when possible, and if a library creates listeners per usage, contact maintainer or add cleanup by calling provided close/destroy functions on request completion.

4

Diagnostic step 4

Add listener leak detection during development: process.setMaxListeners and checks for increasing counts, and deploy memory limit restarts as a temporary mitigation while fixing code.

5

Diagnostic step 5

If the leak source is a native addon or opaque third-party module, collect reproducible minimal test and escalate to a senior developer or the module author with heap snapshots and reproduction steps; avoid speculative rewrites in production without backups and blue/green deployment capability.