oxc-project/oxc · warning · OxcDiagnostic

Prefer top-level await over an async function call.

Error message

Prefer top-level await over an async function call.

What it means

This is the async-function-call diagnostic of oxlint's `unicorn/prefer-top-level-await`. It fires when a module top-level statement calls an async function (a function declared `async`, or returning a promise) without awaiting it — the floating-promise pattern — and suggests adding `await` before the call ('Add `await` before the function call.').

Source

Thrown at crates/oxc_linter/src/rules/unicorn/prefer_top_level_await.rs:23

use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};

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

fn prefer_top_level_await_over_promise_chain_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Prefer top-level await over using a promise chain.").with_label(span)
}

fn prefer_top_level_await_over_async_iife_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Prefer top-level await over using an async IIFE.").with_label(span)
}

fn prefer_top_level_await_over_async_function_call_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Prefer top-level await over an async function call.")
        .with_help("Add `await` before the function call.")
        .with_label(span)
}

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

declare_oxc_lint!(
    /// ### What it does
    ///
    /// Prefer top-level await over top-level promises and async function calls.
    ///
    /// ### Why is this bad?
    ///
    /// Top-level await is more readable and can prevent unhandled rejections.
    ///
    /// ### Examples
    ///

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Add `await`: `await init();`.
  2. If fire-and-forget is intentional, make it explicit with `void init();` (many configs accept `void`) or attach `.catch()` to handle rejection, then disable the rule for that line.
  3. If other top-level code should not block, restructure so dependents import a promise and await it themselves.
  4. For CJS files where TLA is unavailable, disable `unicorn/prefer-top-level-await`.

Example fix

// before
init();

// after
await init();
Defensive patterns

Strategy: validation

Validate before calling

// Make floating async calls explicit
await init();          // blocking, ordered
void init();           // intentional fire-and-forget
init().catch(log);     // fire-and-forget with rejection handling

Type guard

// Narrow before calling at top level: is it actually async?
function returnsPromise(fn) {
  return typeof fn === 'function' && fn.constructor.name === 'AsyncFunction';
}

Prevention

When it happens

Trigger: A top-level expression statement or initializer whose callee is an `async` function declaration/identifier invoked without `await` (e.g. `init();` where `async function init() {}`); the rule matches the call via method/identifier checks at module scope.

Common situations: Bootstrap scripts calling `connect();` or `warmCache();` that are actually async — the module finishes evaluating before the work completes, causing races with imports that depend on the side effect. Common when converting scripts to ESM where ordering guarantees of top-level await matter.

Related errors


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