#5925·mocha

Bug: parent-suite teardown error masks original failure from nested suite

Author: IlyasShabiCreated Apr 29, 2026Updated Sep 13, 2026
Labelstype: bugstatus: accepting prs

Bug Report Checklist

Expected

When a test or hook inside a nested describe() fails, and a teardown hook registered on a parent suite also fails afterward, Mocha should keep the original nested failure as the primary reported error.

The parent teardown error is secondary. It should not obscure the failure that actually caused the test run to become unhealthy.

This is a common layout in larger test suites:

javascript
describe('outer suite', () => {
  afterEach(() => cleanup())

  describe('inner suite', () => {
    beforeEach(() => setup())

    it('does something', () => {})
  })
})

If the nested setup/test fails, and the parent cleanup also throws, the original nested failure is the useful root cause.

Actual

Mocha reports the parent teardown failure as an additional failure after the original nested failure. In large CI logs this makes the teardown cascade look like an independent failure and can obscure the actual root cause.

    outer suite
      inner suite
        1) "before each" hook for "does something"
      2) "after each" hook for "does something"

    0 passing
    2 failing

    1) outer suite inner suite
         "before each" hook for "does something":
       Error: inner setup failed

    2) outer suite
         "after each" hook for "does something":
       Error: outer cleanup failed

The second error is a teardown cascade. The first error is the root cause.

Minimal, Complete and Verifiable Example

javascript
const { describe, beforeEach, afterEach, it } = require('mocha')

describe('outer suite', () => {
  afterEach(() => {
    throw new Error('outer cleanup failed')
  })

  describe('inner suite', () => {
    beforeEach(() => {
      throw new Error('inner setup failed')
    })

    it('does something', () => {})
  })
})
javascript
const { describe, after, it } = require('mocha')

describe('outer suite', () => {
  after(() => {
    throw new Error('outer cleanup failed')
  })

  describe('inner suite', () => {
    it('fails for the real reason', () => {
      throw new Error('inner test failed')
    })
  })
})

Versions

  • Mocha 11.7.5
  • Node.js v24.13.0

Additional Info

This is related to #5922, but the nested-suite case is slightly different: the original failure is not necessarily in the same suite where the teardown hook was registered.