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:
/// ```javascriptView on GitHub (pinned to e1e7af627c)
Solutions
- 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); })`.
- If the body awaits several steps, hoist them into a separate async function and call it from a non-async executor.
- If the whole Promise wrapper is unnecessary, return the async function's promise directly instead of wrapping it in `new Promise`.
- 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
- Treat `new Promise(...)` as a last resort; prefer async functions that return values directly.
- Enable the eslint `correctness` category in oxlint so this is caught at commit time.
- In review, grep new PRs for `new Promise\s*\(\s*async`.
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
- Unexpected `await` inside a loop.
- Avoid nesting promises.
- Do not use `new` on `Promise.{static_name}`
- Avoid using promises inside of callbacks.
- Don't return in a finally callback
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/69f900969e12acbc.
Report an issue: GitHub.