oxc-project/oxc · error · OxcDiagnostic

Promise executor functions should not be `async`.

Error message

Promise executor functions should not be `async`.

What it means

Diagnostic from the oxlint rule `no-async-promise-executor` (eslint plugin, crates/oxc_linter/src/rules/eslint/no_async_promise_executor.rs). It fires when the executor function passed to `new Promise(...)` is declared `async`. The Promise constructor ignores the executor's returned promise, so an async executor that throws produces an unhandled rejection instead of rejecting the constructed promise, and resolution ordering can silently diverge from what the code implies.

Source

Thrown at crates/oxc_linter/src/rules/eslint/no_async_promise_executor.rs:12

use oxc_ast::{
    AstKind,
    ast::{Argument, Expression},
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;

use crate::{AstNode, context::LintContext, rule::Rule};

fn no_async_promise_executor_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Promise executor functions should not be `async`.")
        .with_help("Remove the `async` keyword from the Promise executor function.")
        .with_label(span)
}

#[derive(Debug, Default, Clone)]
pub struct NoAsyncPromiseExecutor;

declare_oxc_lint!(
    /// ### What it does
    ///
    /// Disallow using an async function as a Promise executor.
    ///
    /// ### Why is this bad?
    ///
    /// The `new Promise` constructor accepts an executor function as an argument,
    /// which has `resolve` and `reject` parameters that can be used to control the state of the
    /// created Promise. For example:
    /// ```javascript

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Remove the `async` keyword from the executor and use plain `.then()` chains or call an async helper inside, e.g. `new Promise((resolve, reject) => { doAsync().then(resolve, reject); })`.
  2. If the body awaits several steps, hoist them into a separate async function and call it from a non-async executor.
  3. If the whole Promise wrapper is unnecessary, return the async function's promise directly instead of wrapping it in `new Promise`.
  4. If the pattern is intentional and handled, suppress with an inline `// oxlint-disable-next-line no-async-promise-executor` comment.

Example fix

// before
const p = new Promise(async (resolve, reject) => {
  const data = await fetchData();
  resolve(data);
});

// after
const p = new Promise((resolve, reject) => {
  fetchData().then(resolve, reject);
});
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check before lint: flag async executors before they ship
const src = fs.readFileSync(file, 'utf8');
const badAsyncExecutor = /new\s+Promise\s*\(\s*async\b/.test(src);
if (badAsyncExecutor) failFast('async Promise executor in ' + file);

Prevention

When it happens

Trigger: Any node matching `new Promise(async (resolve, reject) => {...})` or `new Promise(async function (resolve, reject) {...})` — i.e. the first Argument of a NewExpression whose callee resolves to global `Promise` is a FunctionExpression/ArrowFunctionExpression with an async marker.

Common situations: Refactoring promise chains into async/await and leaving the async keyword on the executor; copy-pasting an async helper into a Promise constructor; code migrated from ESLint projects where the same rule already flagged it; enabling the `correctness` category of oxlint on an existing codebase.

Related errors


AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20). Data as JSON: /api/errors/69f900969e12acbc. Report an issue: GitHub.