{"record":{"id":"b40ff349553ed97a","repo":"oxc-project/oxc","slug":"unexpected-assignment-to-exports","errorCode":null,"errorMessage":"Unexpected assignment to `exports`.","messagePattern":"Unexpected assignment to `exports`\\.","errorType":"validation","errorClass":"OxcDiagnostic","httpStatus":null,"severity":"error","filePath":"crates/oxc_linter/src/rules/node/exports_style.rs","lineNumber":33,"sourceCode":"    context::LintContext,\n    rule::{Rule, TupleRuleConfig},\n    utils::{is_global_exports_assignment_target, is_global_module_exports},\n};\n\nfn unexpected_exports_diagnostic(span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(\"Unexpected access to `exports`.\")\n        .with_help(\"Use `module.exports` instead.\")\n        .with_label(span)\n}\n\nfn unexpected_module_exports_diagnostic(span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(\"Unexpected access to `module.exports`.\")\n        .with_help(\"Use `exports` instead.\")\n        .with_label(span)\n}\n\nfn unexpected_assignment_diagnostic(span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(\"Unexpected assignment to `exports`.\")\n        .with_help(\"Do not modify `exports` itself.\")\n        .with_label(span)\n}\n\n#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]\n#[serde(rename_all = \"kebab-case\")]\nenum ExportsStyleMode {\n    #[default]\n    #[serde(rename = \"module.exports\")]\n    /// Requires `module.exports` and disallows `exports`\n    ModuleExports,\n    /// Requires `exports` and disallows `module.exports`\n    Exports,\n}\n\n#[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema)]\n#[serde(rename_all = \"camelCase\", default, deny_unknown_fields)]\nstruct ExportsStyleOptions {","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/oxc-project/oxc/blob/e1e7af627c8843ab64044ed466b128fcc21a035b/crates/oxc_linter/src/rules/node/exports_style.rs#L15-L51","documentation":"Diagnostic from oxlint rule node/exports-style, fired in BOTH modes by the shared helper is_global_exports_assignment_target: assigning to the `exports` binding itself is always wrong. In CommonJS `exports` is an alias created at module load; rebinding it (exports = { a: 1 }) exports nothing because require() returns module.exports, which still points at the original object. Unlike the two style diagnostics in this rule, this one catches a real bug and deserves prompt fixing.","triggerScenarios":"An assignment whose target resolves to the module-scope global `exports` — exports = { a: 1 };, exports = something || {}; — regardless of whether the rule's mode option is 'module.exports' or 'exports'. Property writes like exports.a = 1 do NOT trigger this diagnostic (those go to the access diagnostics per mode).","commonSituations":"Developers porting ES-module habits ('export default' feels like assigning the export); scaffolds that write exports = {}; beginners learning CommonJS aliasing; note the dedicated node/no-exports-assign rule reports the same bug with a different message, so enabling both yields two reports on one line.","solutions":["Assign to the real export target: 'module.exports = { a: 1 }'","If you only meant to add to what is exported, mutate instead: 'exports.a = 1' (or module.exports.a = 1)","Keep node/no-exports-assign or this rule enabled in CI to catch regressions — the bug is silent at runtime"],"exampleFix":"// before\nexports = { hello: () => {} }; // require()rs get the ORIGINAL empty object\n\n// after\nmodule.exports = { hello: () => {} };","handlingStrategy":"validation","validationCode":"// .oxlintrc.json — the assignment diagnostic runs in both modes; one of these suffices\n\"rules\": { \"node/no-exports-assign\": \"error\" }\n\nnpx oxlint -c .oxlintrc.json --deny-warning .","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Internalize the rule of thumb: `exports` is read/mutate-only; the only reassignable export target is module.exports","Add a smoke test that require()s each entry-point module and asserts its exports are non-empty — catches reassignment bugs that slip past lint","Keep the dedicated no-exports-assign rule enabled even when exports-style is off"],"tags":["node","commonjs","exports","bug","oxlint"],"backgroundTag":"exports-reassignment","analyzedSha":"e1e7af627c8843ab64044ed466b128fcc21a035b","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}