oxc-project/oxc · warning · OxcDiagnostic
Prefer top-level await over using a promise chain.
Error message
Prefer top-level await over using a promise chain.
What it means
This is the promise-chain diagnostic of oxlint's `unicorn/prefer-top-level-await` rule. In an ES module (where top-level `await` is allowed), it flags promise chains like `fetch(url).then(...)` whose result is used at module top level, and recommends `await`ing the chain directly — removing scheduling indirection and letting you use try/catch and loops around async values.
Source
Thrown at crates/oxc_linter/src/rules/unicorn/prefer_top_level_await.rs:15
use oxc_ast::{
AstKind,
ast::{Expression, VariableDeclarationKind},
};
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
///View on GitHub (pinned to e1e7af627c)
Solutions
- Add `await`: `const config = await (await fetch('/config.json')).json();`.
- Ensure the file is an ES module (`.mjs` or `"type": "module"`) and your runtime/bundler supports top-level await (Node >= 14.8 with ESM flag-free since 16).
- If the parallelism matters (multiple chains started concurrently), use `await Promise.all([...])` instead of sequential awaits.
- Disable the rule with `"unicorn/prefer-top-level-await": "off"` for CJS-flavored code.
Example fix
// before const data = fetch(url).then((r) => r.json()); // after const data = await (await fetch(url)).json();
Defensive patterns
Strategy: validation
Validate before calling
// In ESM, await module-scope async work directly
const config = await (await fetch('/config.json')).json();
// CI: npx oxlint --deny-warn unicorn/prefer-top-level-await src/ Try / catch
// Top-level await participates in normal try/catch at module scope
try {
const config = await loadConfig();
} catch (err) {
handleBootFailure(err);
} Prevention
- Ensure the file is ESM (`.mjs` or `"type": "module"`) before adopting top-level await.
- Use `await Promise.all([...])` to keep concurrent chains parallel.
- Keep top-level awaits near the top of the module — they block importing modules by design.
When it happens
Trigger: A top-level statement (typically `const x = promise.then(...)` — recognized via `variable_declaration_kind` and `is_method_call` for `.then`) in a module context, where the promise chain could be replaced by `const x = await promise...`. The rule only applies at the module top level, not inside functions.
Common situations: Config/module-init code like `const config = fetch('/config.json').then(r => r.json());` in ESM; migrating CommonJS scripts to ESM and modernizing `.then` chains. Requires the file to be a module (`"type": "module"`, `.mjs`, or ESM in the bundler) — in plain CJS scripts top-level await is a syntax error, so the rule's advice does not apply there.
Related errors
- Prefer top-level await over using an async IIFE.
- Prefer top-level await over an async function call.
- Top-level `await` prevents this module from being loaded wit
- Prefer `Blob#{good_method}()` over `FileReader#{bad_method}(
- Async assertions must be awaited.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/4ab3c7d4a83e86cd.
Report an issue: GitHub.