Bug: parent-suite teardown error masks original failure from nested suite
Bug Report Checklist
- This is NOT a security,
npm audit, or GitHub Advisory issue. - I have read and agree to Mocha's Code of Conduct and Contributing Guidelines
- I have searched for related issues and issues with the
faqlabel, but none matched my issue. - I have 'smoke tested' the code to be tested by running it outside the real test suite to get a better sense of whether the problem is in the code under test, my usage of Mocha, or Mocha itself.
- I want to provide a PR to resolve this
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:
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 failedThe second error is a teardown cascade. The first error is the root cause.
Minimal, Complete and Verifiable Example
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', () => {})
})
})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.
Source: mochajs/mocha