Skip to content

fix: log full error object in logerror (fixes #6462)#7290

Open
myselfsiddharth wants to merge 2 commits into
expressjs:masterfrom
myselfsiddharth:fix/logerror-full-error-object-6462
Open

fix: log full error object in logerror (fixes #6462)#7290
myselfsiddharth wants to merge 2 commits into
expressjs:masterfrom
myselfsiddharth:fix/logerror-full-error-object-6462

Conversation

@myselfsiddharth

Copy link
Copy Markdown

Summary

Changes logerror in lib/application.js to use console.error(err) instead of console.error(err.stack || err.toString()), so Node's built-in error inspection preserves Error.cause, custom enumerable properties (e.g. Sequelize parent/original), and AggregateError details.

This matches the approach in #6464 (approved in review; vestigial err.stack workaround from pre-Node-18 when console.error(err) did not print stacks). Express 5 already requires Node >= 18.

This PR is rebased on current master and adds regression test coverage (test/app.logerror.js) for the default error handler logging path.

Fixes #6462

Related PRs

Test plan

  • npm test -- test/app.logerror.js
  • Full suite: npm test (1250 passing)

Behavior note

Only affects stderr when the default error handler runs and env !== 'test'. HTTP responses are unchanged.

@myselfsiddharth

Copy link
Copy Markdown
Author

cc @Nitin-Mohapatra — happy to help rebase #6464 or fold this test into that PR if maintainers prefer a single PR.

@Ap-0007 Ap-0007 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very clean and necessary improvement! Passing the raw error object directly to console.error leverages Node's built-in error inspection (especially with standard Error.cause support since Node 18).

One minor suggestion to make the added test more robust:
In test/app.logerror.js, console.error is mocked inline inside the test case and restored inside the async callbacks:

    var logged
    var original = console.error
    console.error = function (err) {
      logged = err
    }
    ...

If the HTTP request or test times out, or if an unexpected exception occurs before the callbacks are executed, console.error might not be restored, potentially leaking the mock to other tests in the runner.

To ensure global state is always restored, we can use Mocha's standard beforeEach/afterEach hooks:

describe('logerror', function () {
  var original

  beforeEach(function () {
    original = console.error
  })

  afterEach(function () {
    if (original) {
      console.error = original
    }
  })

  it('should log the full error object', function (done) {
    var app = express()
    app.set('env', 'development')

    var logged
    console.error = function (err) {
      logged = err
    }

    app.use(function (req, res, next) {
      var inner = new Error('inner')
      next(new Error('outer', { cause: inner }))
    })

    request(app)
      .get('/')
      .expect(500, function (err) {
        if (err) return done(err)
        setImmediate(function () {
          assert.ok(logged instanceof Error)
          assert.strictEqual(logged.message, 'outer')
          assert.ok(logged.cause instanceof Error)
          assert.strictEqual(logged.cause.message, 'inner')
          done()
        })
      })
  })
})

This guarantees cleanup regardless of whether the assertions pass or the test times out.

@myselfsiddharth

Copy link
Copy Markdown
Author

Good catch, @Ap-0007
Thanks! You're right. if the request times out the mock could leak. I'll move the save/restore into beforeEach / afterEach hooks and push an update shortly.

Use console.error(err) instead of err.stack || err.toString() so Node's built-in error inspection includes Error.cause, custom properties (e.g. Sequelize parent/original), and AggregateError details.

Adds regression test for the default error handler logging path.

Fixes expressjs#6462

Related: expressjs#6464 (same one-line fix; this PR adds test coverage and is rebased on current master)
@myselfsiddharth myselfsiddharth force-pushed the fix/logerror-full-error-object-6462 branch from 83da617 to 6263c0d Compare June 8, 2026 00:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

logError swallows error details (such as cause)

2 participants