Repository: mochajs/mocha (JavaScript)

Issue:
🐛 Bug: `this.parent.titlePath is not a function` during parallel execution with retries
### Bug Report Checklist

- [X] I have read and agree to Mocha's [Code of Conduct](https://github.com/mochajs/mocha/blob/main/.github/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/mochajs/mocha/blob/main/.github/CONTRIBUTING.md)
- [X] I have searched for [related issues](https://github.com/mochajs/mocha/issues?q=is%3Aissue) and [issues with the `faq` label](https://github.com/mochajs/mocha/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3Afaq%20), but none matched my issue.
- [X] 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

I expected to be able to run the test suites in parallel mode using `./bin/mocha --parallel <test/files>` without failure in v10.6.0

### Actual

The tests are failing with:
```text
1) Uncaught error outside test suite:
     Uncaught TypeError: this.parent.titlePath is not a function
      at Array.forEach (<anonymous>)
```

With `--full-trace` CLI option, it shows _(I snipped the project name)_
```text
1) Uncaught error outside test suite:
     Uncaught TypeError: this.parent.titlePath is not a function
      at Runnable.titlePath (/home/rdn/Projects/<snipped>/node_modules/mocha/lib/runnable.js:217:22)
      at Runnable.fullTitle (/home/rdn/Projects/<snipped>/node_modules/mocha/lib/runnable.js:206:15)
      at Test.serialize (/home/rdn/Projects/<snipped>/node_modules/mocha/lib/test.js:94:23)
      at SerializableEvent.serialize (/home/rdn/Projects/<snipped>/node_modules/mocha/lib/nodejs/serializer.js:256:27)
      at /home/rdn/Projects/<snipped>/node_modules/mocha/lib/nodejs/serializer.js:72:13
      at Array.forEach (<anonymous>)
      at SerializableWorkerResult.serialize (/home/rdn/Projects/<snipped>/node_modules/mocha/lib/nodejs/serializer.js:71:17)
      at serialize (/home/rdn/Projects/<snipped>/node_modules/mocha/lib/nodejs/serializer.js:366:15)
      at /home/rdn/Projects/<snipped>/node_modules/mocha/lib/nodejs/worker.js:127:28
      at ParallelBuffered.done (/home/rdn/Projects/<snipped>/node_modules/mocha/lib/nodejs/reporters/parallel-buffered.js:151:5)
```

Note that I tested this multiple times in 10.4.0 and 10.5.1 versions and I could not reproduce even after exhaustive attempts.

### Minimal, Reproducible Example

I was not able to find 100% reproducible steps in my local machine, as it is not giving me consistent behavior, failing around 40% of the time in different test suites.
However in our CI environment (6 vCPU + 16GB RAM machines) it is failing at all times when using 6 parallel jobs, in different test suites.

So I could not find a specific code to trigger it

### Versions

Versions:
```console
$ mocha --version
bash: mocha: command not found
$ npx mocha --version
10.6.0
$ node_modules/.bin/mocha --version
10.6.0
$ node --version
v22.4.0
```
Shell: Bash (5.2.026-5) (ArchLinux)

Related modules: JS with ESModules

### Additional Info

During my own debugging of the mocha v10.6.0 directly installed in `node_modules`, I was able to add some debugging info and found that at [this line](https://github.com/mochajs/mocha/blob/c43930cc6dc41980f4fcf054d506d780a28a72df/lib/runnable.js#L217), `this.parent` is actually a _string_ with value `"[Circular]"` (without quotes), thus failing when trying to access the function `this.parent.titlePath()`.

I could not find the error in v10.4.0 or v10.5.1 (I did not test v10.5.0)


Discussion:
I didnt want to speculate in the OG issue (so we could delete this comment if that is against CoC), but I compared the changes from 10.4.0 to 10.6.0 and I squint my eyes when I look at [this code added on 10.6.0](https://github.com/mochajs/mocha/blob/c43930cc6dc41980f4fcf054d506d780a28a72df/lib/utils.js#L666) which seems very hard to test
cc @sam-super @voxpelli from that PR.

I believe you that this bug exists, but without a reproduction, there's really not much we can do to fix it 😞. @ReDemoNBR we'd be happy to sign an NDA if that'd help getting readonly access to your CI logs and project setup. Marking as waiting for more info in the meantime.

Thanks for trying out the latest Mocha & filing! 🤎 
Even though the project is not open source, the company is open source friendly so no NDA is needed, just your word should be enough

For more info that I can give here, there are 308 test suites with 1115 tests in total.

To be honest, there is not much logs in GitLab CI as the `--full-trace` is not enabled (risk of full error tracing printing credentials or secrets), but I can try to record it myself and send it your way along with the full CI logs (about 2k lines each run), or schedule a meeting where I can screenshare and do it live (walk you through it, do some more debugging etc) in my Brazilian timezone (UTC-0300).
I'd be happy to help

You may contact me in private using the email address in my profile
My team has been encountering this issue.
I have found that mocha `10.5.1` works, but `10.5.2` returns the error.

Using mocha `10.5.2`:

package.json
```
{
  "name": "testing",
  "version": "1.0.0",
  "description": "Test Scripts",
  "license": "UNLICENSED",
  "devDependencies": {
    "chai": "4.4.1",
    "mocha": "10.5.2"
  }
}
```

.mocharc.json
```
{
  "diff": true,
  "parallel": true,
  "extension": ["js"],
  "package": "./package.json",
  "timeout": "60000",
  "retries": 1
}
```

test-file.js
```
const { expect } = require('chai');

describe(`Test File`, () => {
  it(`Test`, async () => {
    expect(1).to.equal(2);
  });
});
```

command: `npx mocha .\test-file.js`

Result:
```
1) Uncaught error outside test suite

  0 passing (321ms)
  1 failing

  1) Uncaught error outside test suite:
     Uncaught TypeError: this.parent.titlePath is not a function
      at Array.forEach (<anonymous>)
```

If I switch mocha to `10.5.1` I get:
```
  Test File
    1) Test


  0 passing (323ms)
  1 failing

  1) Test File
       Test:

      AssertionError: expected 1 to equal 2
      + expected - actual

      -1
      +2

      at Context.<anonymous> (test-file.js:5:18)
      at process.processImmediate (node:internal/timers:478:21)
```
Note also https://github.com/mochajs/mocha/pull/5032#issuecomment-2194460479:

> ```
>   1) Uncaught error outside test suite:
>      Uncaught TypeError: this.parent.titlePath is not a function
>       at Test.Runnable.titlePath (/node_modules/mocha/lib/runnable.js:217:22)
>       at Test.Runnable.fullTitle (/node_modules/mocha/lib/runnable.js:206:15)
>       at Test.serialize (/node_modules/mocha/lib/test.js:94:23)
>       at SerializableEvent.serialize (/node_modules/mocha/lib/nodejs/serializer.js:256:27)
>       at /node_modules/mocha/lib/nodejs/serializer.js:72:13
>       at Array.forEach (<anonymous>)
>       at SerializableWorkerResult.serialize (/node_modules/mocha/lib/nodejs/serializer.js:71:17)
>       at serialize (/node_modules/mocha/lib/nodejs/serializer.js:366:15)
>       at /node_modules/mocha/lib/nodejs/worker.js:127:28
>       at ParallelBuffered.done (/node_modules/mocha/lib/nodejs/reporters/parallel-buffered.js:151:5)
> ```

I see the issue, and will send a PR soon. Thanks for posting everyone! Seeing the different inputs on how this could happen was very useful. 🙂 
I tested https://github.com/mochajs/mocha/pull/5173#pullrequestreview-2170834875 in my project and it worked.
Basically I made a .patch file with the diff and applied in CI with `patch -u node_modules/mocha/lib/nodejs/serializer.js -i mocha.patch` before running the tests.

<details>
<summary>mocha@10.6.0</summary>

![2024-07-11 00 28 22 gitlab com 5fcb8945380a](https://github.com/mochajs/mocha/assets/9003359/f9b342ee-4c0c-4ed6-b6d1-e8e76fbddee6)
</details>
<details>
<summary>mocha@10.6.0 + patch from PR #5173 applied</summary>

![2024-07-11 00 28 35 gitlab com 7fe1e12cd841](https://github.com/mochajs/mocha/assets/9003359/8114280e-da4e-4938-acf2-50739aad9830)
</details>





Patch:
diff --git a/lib/nodejs/serializer.js b/lib/nodejs/serializer.js
index 25d2e39727..63e1a24e51 100644
--- a/lib/nodejs/serializer.js
+++ b/lib/nodejs/serializer.js
@@ -259,7 +259,7 @@ class SerializableEvent {
     });
 
     // mutates the object
-    breakCircularDeps(result);
+    breakCircularDeps(result.error);
 
     const pairs = Object.keys(result).map(key => [result, key]);
 


Test patch:
diff --git a/test/integration/fixtures/parallel/non-circular-error.mjs b/test/integration/fixtures/parallel/non-circular-error.mjs
new file mode 100644
index 0000000000..251a58b0fd
--- /dev/null
+++ b/test/integration/fixtures/parallel/non-circular-error.mjs
@@ -0,0 +1,5 @@
+import {it} from '../../../../index.js';
+
+it('test', () => {
+  throw new Error('Foo');
+});
diff --git a/test/integration/parallel.spec.js b/test/integration/parallel.spec.js
index 5dc1d07fcd..fad184e24b 100644
--- a/test/integration/parallel.spec.js
+++ b/test/integration/parallel.spec.js
@@ -43,4 +43,19 @@ describe('parallel run', () => {
     assert.strictEqual(result.failures[0].err.message, 'Foo');
     assert.strictEqual(result.failures[0].err.foo.props[0], '[Circular]');
   });
+
+  it('should correctly handle an exception with retries', async () => {
+    const result = await runMochaJSONAsync('parallel/circular-error.mjs', [
+      '--parallel',
+      '--jobs',
+      '2',
+      '--retries',
+      '1',
+      require.resolve('./fixtures/parallel/testworkerid1.mjs')
+    ]);
+    assert.strictEqual(result.stats.failures, 1);
+    assert.strictEqual(result.stats.passes, 1);
+    assert.strictEqual(result.failures[0].err.message, 'Foo');
+    assert.strictEqual(result.failures[0].err.foo.props[0], '[Circular]');
+  });
 });