{"record":{"id":"421b31e1ce8c0b85","repo":"mochajs/mocha","slug":"async-skip-aborting-execution","errorCode":null,"errorMessage":"async skip; aborting execution","messagePattern":"async skip; aborting execution","errorType":"exception","errorClass":"PendingError","httpStatus":null,"severity":"warning","filePath":"lib/runnable.js","lineNumber":328,"sourceCode":"    if (this.fn && typeof this.fn.call !== \"function\") {\n      done(\n        new TypeError(\n          \"A runnable must be passed a function as its second argument.\",\n        ),\n      );\n      return;\n    }\n\n    // explicit async with `done` argument\n    if (this.async) {\n      this.resetTimeout();\n\n      // allows skip() to be used in an explicit async context\n      this.skip = function asyncSkip() {\n        this.pending = true;\n        done();\n        // halt execution, the uncaught handler will ignore the failure.\n        throw new PendingError(\"async skip; aborting execution\");\n      };\n\n      try {\n        callFnAsync(this.fn);\n      } catch (err) {\n        // handles async runnables which actually run synchronously\n        errorWasHandled = true;\n        if (err instanceof PendingError) {\n          return; // done() is already called in this.skip()\n        } else if (this.allowUncaught) {\n          throw err;\n        }\n        done(Runnable.toValueOrError(err));\n      }\n      return;\n    }\n\n    // sync or promise-returning","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/mochajs/mocha/blob/6bcbee4fd9a95351cedf0fdcb14c7d696486bc5a/lib/runnable.js#L310-L346","documentation":"Inside async runnable execution, Mocha installs `this.skip` as an `asyncSkip` function that fires `done()` and throws a `PendingError` to halt the remaining function body. The thrown error is intentionally ignored by Mocha's uncaught handler so the test is reported as pending; it surfaces as a problem only when that sentinel escapes Mocha's bookkeeping.","triggerScenarios":"Calling `this.skip()` inside an async test's promise/`done` flow (`it('...', function(done){ ...; this.skip(); })`); using `this.skip()` inside a callback where the arrow-function binding loses `this`; custom promise chains rethrowing the PendingError after Mocha's handler ran.","commonSituations":"Conditional skipping in async tests; mixing arrow functions (`this` undefined so fallback paths misbehave); test frameworks (e.g. old webdriver/selenium wrappers) that intercept thrown errors before Mocha's uncaught handler.","solutions":["Use a regular function (not arrow) so `this.skip` binds correctly.","In async tests, call `this.skip()` and `return` immediately; don't continue executing code afterward.","For promise-based tests, prefer `ctx.skip()` via `it` context or mark with `it.skip` when possible.","Ensure no wrapper rethrows PendingError into Mocha as a normal failure; treat `err.message === 'async skip; aborting execution'` as a skip."],"exampleFix":"// before\nit('loads', async function () {\n  if (!server) this.skip(); // arrow/continued execution can leak the sentinel\n  await load();\n});\n\n// after\nit('loads', async function () {\n  if (!server) return this.skip();\n  await load();\n});","handlingStrategy":"try-catch","validationCode":"if (typeof this.skip !== 'function' || this.constructor === ArrowContext) {\n  throw new Error('async this.skip() requires a non-arrow function test with Mocha context');\n}","typeGuard":"const isPendingError = (err) => err instanceof Error && /skip; aborting execution/.test(err.message);","tryCatchPattern":"try {\n  await asyncTestBody();\n} catch (err) {\n  if (isPendingError(err)) {\n    reportPending(test);\n    return;\n  }\n  throw err;\n}","preventionTips":["Use function expressions (not arrows) so `this.skip` is available.","In async tests, `return this.skip()` and stop execution immediately.","Don't let generic promise `.catch()` handlers rethrow the sentinel.","Prefer it.skip or a skip helper that sets pending without throwing when possible."],"tags":["test-execution","skip","async"],"backgroundTag":"test-skipped-sentinel","analyzedSha":"6bcbee4fd9a95351cedf0fdcb14c7d696486bc5a","analyzedAt":"2026-09-01T03:41:47.182Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}