Skip to content

error handler of same domain can be called several times when it throws #25505

Description

@misterdjules
  • Version: Current tip of master (66f45e7), but probably applies to all versions.
  • Platform: All platforms.
  • Subsystem: domain.

The following code:

'use strict';

const common = require('../common');
const domain = require('domain');
const http = require('http');

const server = http.createServer((req, res) => {
  res.end();
});

let numDomainErrorListenerCalls = 0;

function performHttpRequestWithDomain(cb) {
  const d = domain.create();
  d.run(() => {
    const req = http.get({
      host: '127.0.0.1', port: server.address().port
    }, (res) => {
      res.on('data', () => {});
      res.on('end', () => {
        throw new Error('bang');
      });
    });

    req.end();
  });

  d.on('error', (domainErr) => {
    console.log(++numDomainErrorListenerCalls);
    throw new Error('boom');
  });
}

server.listen(0, '127.0.0.1', () => {
  performHttpRequestWithDomain(common.mustCall(() => {
    server.close();
  }));
});

gives the following output:

$ ./node test/parallel/test-http-req-domain-stack.js 
1
2
/Users/jgilli/dev/node/test/parallel/test-http-req-domain-stack.js:30
    throw new Error('boom');
    ^

Error: boom
    at Domain.d.on (/Users/jgilli/dev/node/test/parallel/test-http-req-domain-stack.js:30:11)
    at Domain.emit (events.js:188:13)
    at Domain.EventEmitter.emit (domain.js:430:20)
    at Domain._errorHandler (domain.js:216:23)
    at Domain._errorHandler (domain.js:244:33)
    at Object.setUncaughtExceptionCaptureCallback (domain.js:132:29)
    at process._fatalException (internal/process/execution.js:102:29)

The uncaught exception is expected. What is not expected as far as I understand is for the same domain's error handler to run more than once.

I believe the original intention of the domain's implementation is to pop the domains stack when a domain's error handler throw, so that the domain that handles that new error is the "parent" domain.

However, in the example above the same domain is pushed on the stack more than once. For instance, when an event is emitted from a nextTick callback, the same domain will be entered from the nextTick callbacks scheduler and then once again from the event emitter.

Pushing the same domain on the stack more than once makes sense so that the components that push a domain can pop it from the stack. However, I think we could probably replace the call to pop the stack once in the domain error handling code to remove all consecutive instances of that domain instead.

@nodejs/domains Thoughts?

Activity

  1. added
    domainIssues and PRs related to the domain subsystem.
    on Jan 15, 2019
  2. added
    help wantedIssues that need assistance from volunteers or PRs that need help to proceed.
    on Jun 26, 2020
  3. shriyaagg commented on Oct 21, 2025

    @shriyaagg

    i would like to work on this issue, thank you

  4. keyuyan1145 commented on Jun 10, 2026

    @keyuyan1145

    Hey! I'm fairly new to open source but have a few years of industry experience under my belt. Is this issue still open and unassigned? I'd love to take a shot at it and submit a PR!

  5. luanmuniz commented on Jun 27, 2026

    @luanmuniz
    Contributor

    I tried reproducing this on current Node.js main / v27.0.0-pre and 26.3.0, and I don’t seem to be able to reproduce the issue anymore.

    Using the code from the issue, I now get:

    1
    /path/to/test.js:30
        throw new Error('boom');
        ^
    
    Error: boom
        at Domain.<anonymous> (/path/to/test.js:30:11)
        at Domain.emit (node:events:509:20)
        at Domain.emit (node:domain:473:12)
        at Domain._errorHandler (node:domain:263:23)
        at Object.<anonymous> (node:domain:165:29)
        at process._fatalException (node:internal/process/execution:179:29)
    

    I do not see the previous behavior where the handler was called twice and printed both 1 and 2.

    From my understanding, that is the original bang error should be handled by the domain, but an error thrown from that domain’s own error handler should not re-enter the same handler.

    I might be missing something, but I think this issue may be fixed now. Can someone check and maybe close this issue?

  6. github-actions commented on Sep 26, 2026

    @github-actions
    Contributor

    This issue has been marked as stale due to 90 days of inactivity.
    It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.

  7. added
    staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.
    on Sep 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domainIssues and PRs related to the domain subsystem.help wantedIssues that need assistance from volunteers or PRs that need help to proceed.staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions