oxc-project/oxc · warning · OxcDiagnostic

Expected {name} instead of {actual}

Error message

Expected {name} instead of {actual}

What it means

Diagnostic from the oxlint rule import/no-commonjs (restriction category). It enforces ESM syntax and reports CommonJS usage: `require()` calls produce "Expected import instead of require" and `module.exports`/`exports.*` usage produces "Expected export instead of exports". Options: `allowRequire` (default false), `allowPrimitiveModules` (default false), and `allowConditionalRequire` (default true — require inside if/try/logical/ternary is allowed).

Source

Thrown at crates/oxc_linter/src/rules/import/no_commonjs.rs:19

use oxc_ast::{
    AstKind,
    ast::{Argument, Expression},
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};
use oxc_str::static_ident;
use schemars::JsonSchema;
use serde::Deserialize;

use crate::{
    AstNode,
    context::LintContext,
    rule::{DefaultRuleConfig, Rule},
};

fn no_commonjs_diagnostic(span: Span, name: &str, actual: &str) -> OxcDiagnostic {
    OxcDiagnostic::warn(format!("Expected {name} instead of {actual}"))
        .with_help("Do not use CommonJS `require` calls and `module.exports` or `exports.*`")
        .with_label(span)
}

#[derive(Debug, Clone, JsonSchema, Deserialize)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
pub struct NoCommonjs {
    /// If `allowPrimitiveModules` option is set to true, the following is valid:
    ///
    /// ```js
    /// module.exports = "foo";
    /// module.exports = function rule(context) {
    ///   return { /* ... */ };
    /// };
    /// ```
    ///
    /// but this is still reported:
    ///

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Convert the file to ESM: `require(x)` → `import ... from "x"`, `module.exports = v` → `export default v`, `exports.k = v` → `export const k = v`
  2. Scope the rule off for genuinely-CJS files via config overrides (e.g. *.cjs, *.config.js) instead of editing the code
  3. If requires must stay, relax with options: `{ "allowRequire": true, "allowPrimitiveModules": true }`
  4. Keep intentional lazy loads inside if/try blocks, which `allowConditionalRequire` (default true) already permits

Example fix

// before
var mod = require("./mod");
module.exports = { hello: function () { return "Hello"; } };

// after
import mod from "./mod";
export function hello() { return "Hello"; }
Defensive patterns

Strategy: validation

Validate before calling

// fail fast in CI before lint: refuse new CJS in ESM sources
// package.json script: "check:cjs": "node -e \"const g=require('child_process').execSync;const r=g('rg -l \\"module.exports|require\\" src --type js -g \\"!*.cjs\\" || true').toString().trim();if(r){console.error('CJS found:\\n'+r);process.exit(1)}\""

Prevention

When it happens

Trigger: Top-level `var mod = require("fs")`; `module.exports = {...}` or `module.exports = "Hola"` or `exports.sayHello = function(){}` (when the member expression object is exactly the identifier `module` with property `exports`). Conditional requires inside `if`/`try`/`&&`/ternary pass by default. Emitted from no_commonjs_diagnostic at crates/oxc_linter/src/rules/import/no_commonjs.rs:19.

Common situations: Migrating a CommonJS Node project to ESM ("type": "module") and cleaning up leftovers; mixed codebases where config files (jest.config.js, .eslintrc.js, gulpfile) are still CJS; linting scripts that reuse browser-incompatible CJS patterns.

Related errors


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