oxc-project/oxc · warning
Prefer `async`/`await` to the callback pattern
Error message
Prefer `async`/`await` to the callback pattern
What it means
Diagnostic from oxlint's port of eslint-plugin-promise's prefer-await-to-callbacks style rule. It reports three callback shapes: calls to a function named `cb`/`callback`, function declarations whose LAST parameter is named `cb`/`callback` (callback-taking definitions), and calls whose last argument is a function whose FIRST parameter is named `err`/`error` when the call is not already inside await/yield. Event wiring (on/once/addEventListener/removeEventListener), array iterators (map/filter/forEach/some/every/find) and lodash-style `_.map` are exempted.
Source
Thrown at crates/oxc_linter/src/rules/promise/prefer_await_to_callbacks.rs:13
use oxc_ast::{
AstKind,
ast::{Argument, Expression, FormalParameters, MemberExpression},
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::NodeId;
use oxc_span::{GetSpan, Span};
use crate::{AstNode, context::LintContext, rule::Rule};
fn prefer_await_to_callbacks(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Prefer `async`/`await` to the callback pattern")
.with_help("Refactor to use an `async` function with `await` instead of passing callbacks for cleaner error handling and control flow.")
.with_label(span)
}
#[derive(Debug, Default, Clone)]
pub struct PreferAwaitToCallbacks;
declare_oxc_lint!(
/// ### What it does
///
/// The rule encourages the use of `async/await` for handling asynchronous code
/// instead of traditional callback functions. `async/await`, introduced in ES2017,
/// provides a clearer and more concise syntax for writing asynchronous code,
/// making it easier to read and maintain.
///
/// ### Why is this bad?
///
/// Using callbacks can lead to complex, nested structures known as "callback hell,"View on GitHub (pinned to e1e7af627c)
Solutions
- Refactor the call site to an awaited promise: promisify the API or use its .async/.promises variant, then `const data = await doThing(arg)`.
- Refactor the definition to return a Promise instead of taking a callback: `async function getData(id) { ... }`.
- If the callback's first parameter is not an error, rename it (e.g. `(_, result)` or a meaningful name).
- For irreducibly callback-based APIs (event emitters, array iteration are already exempt), disable the rule or suppress inline.
Example fix
// before
fetchData((err, data) => {
if (err) throw err;
render(data);
});
// after
const data = await fetchData();
render(data); Defensive patterns
Strategy: validation
Validate before calling
oxlint --promise-plugin src/ # prefer-await-to-callbacks
Try / catch
// when a callback API is unavoidable at the edge, contain it:
const fetchData = () =>
new Promise((resolve, reject) => {
api.call((err: Error | null, data: unknown) =>
err ? reject(err) : resolve(data));
});
// callers then `await fetchData()` Prevention
- Promisify library boundaries once (util.promisify or a Promise wrapper) instead of suppressing per call.
- Avoid naming callbacks cb/callback in new APIs — the rule keys on those names.
- Remember the exemptions (event on/once/addEventListener, array map/filter/...) so legitimate callbacks do not push you toward disabling the rule.
When it happens
Trigger: Per the run() visitor: `cb()` / `callback()` callee identifiers; `function getData(id, callback) {}` or `const f = (cb) => {}` last-param named cb/callback; `heart(function(err) {})` / `customMap(errors, (err) => ...)` — a call with a trailing function whose first param is err/error, not under an await/yield ancestor. Passing `something => {}` (non-err name) does not fire; `.map(err => ...)`, `socket.on("error", err => ...)` are exempt.
Common situations: Codebases mid-migration from callback APIs (older Node libs, AWS SDK v2, redis clients) to promise APIs; wrapping libraries that only offer callbacks; callbacks that are not error-first (renaming the param avoids the report).
Related errors
- `VirtualFree` failed during cleanup: {err}
- Tried to get an allocator from an empty `FixedSizeAllocatorP
- Expected error to be handled.
- Enforce `test` and `it` usage conventions
- Use `{preferred_node_name}` instead.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/351669f9bde61a80.
Report an issue: GitHub.