oxc-project/oxc · warning · OxcDiagnostic
Unexpected sync method: '{property_name}'.
Error message
Unexpected sync method: '{property_name}'. What it means
Diagnostic from oxlint rule node/no-sync (style). It flags calls to *Sync-suffixed methods (fs.readFileSync, child_process.execSync, ...) inside functions: synchronous IO blocks Node's single-threaded event loop for the whole call, stalling every concurrent request. The message interpolates the exact property name being called. Options: allowAtRootLevel permits sync calls in top-level script code, and ignores allowlists method names.
Source
Thrown at crates/oxc_linter/src/rules/node/no_sync.rs:19
use rustc_hash::FxHashSet;
use schemars::JsonSchema;
use serde::Deserialize;
use oxc_ast::{AstKind, ast::Expression};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use oxc_str::CompactStr;
use crate::{
AstNode,
ast_util::get_enclosing_function,
context::LintContext,
rule::{DefaultRuleConfig, Rule},
};
fn no_sync_diagnostic(span: Span, property_name: &str) -> OxcDiagnostic {
OxcDiagnostic::warn(format!("Unexpected sync method: '{property_name}'.")).with_label(span)
}
#[derive(Debug, Default, Clone, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
struct NoSyncConfig {
/// Whether synchronous methods should be allowed at the top level of a file.
allow_at_root_level: bool,
/// Function names to ignore.
ignores: FxHashSet<CompactStr>,
}
#[derive(Debug, Default, Clone, Deserialize)]
pub struct NoSync(Box<NoSyncConfig>);
declare_oxc_lint!(
/// ### What it does
///
/// Disallows synchronous methods from being called in Node.js code.View on GitHub (pinned to e1e7af627c)
Solutions
- Switch to the async API and await it: 'const d = await fs.promises.readFile(p, "utf8")'
- Keep sync calls confined to one-shot CLI/bootstrap code and enable { "allowAtRootLevel": true } for those directories (or scope the rule to server code only)
- Silence deliberate cases via the ignores option with the exact method names: "node/no-sync": ["error", { "ignores": ["readFileSync"] }]
- Move expensive load-time work (parsing big JSON, requiring heavy modules) into startup, not per-request paths
Example fix
// before
app.get('/report', (req, res) => {
const data = fs.readFileSync('./data.json', 'utf8'); // blocks the event loop
res.send(data);
});
// after
app.get('/report', async (req, res) => {
const data = await fs.promises.readFile('./data.json', 'utf8');
res.send(data);
}); Defensive patterns
Strategy: validation
Validate before calling
// .oxlintrc.json — strict for server code
"rules": { "node/no-sync": "error" }
// permissive for scripts/
"overrides": [{
"files": ["scripts/**"],
"rules": { "node/no-sync": ["error", { "allowAtRootLevel": true, "ignores": ["readFileSync"] }] }
}]
npx oxlint -c .oxlintrc.json --deny-warning . Prevention
- Default to the promise APIs (fs.promises.*) so the sync variant is never the autocomplete pick
- Keep one-shot sync IO in startup or CLI scripts only; request handlers must stay async end to end
- Load-test any endpoint that touches the filesystem to surface event-loop stalls the compiler cannot see
When it happens
Trigger: A member-expression call whose property name ends in 'Sync' — the diagnostic message embeds the property, e.g. "Unexpected sync method: 'readFileSync'." — located inside a function (get_enclosing_function finds a function parent). Not reported when allowAtRootLevel is true and the call sits at file top level, or when the callee matches the ignores set.
Common situations: One-off scripts copy-pasted into Express/Fastify handlers where they now stall concurrency; build-tool utilities reused at runtime; migrations from eslint-plugin-n where the ignores allowlist must be re-provided in camelCase JSON; sync JSON requires of big files on the request path.
Related errors
- Unexpected `await` inside a loop.
- Top-level `await` prevents this module from being loaded wit
- Async assertions must be awaited.
- Promises which return async assertions must be awaited.
- Change to `throw new TypeError(...)`
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/24d1ef4f2aa9d07c.
Report an issue: GitHub.