oxc-project/oxc · warning
Unexpected redeclaration of read-only global variable.
Error message
Unexpected redeclaration of read-only global variable.
What it means
Reports a var or function declaration at global script scope whose name collides with a read-only global (built-in or configured readonly). Redeclaring built-ins like function Promise() {} overrides the real global for every other script in the runtime, so the rule flags it as 'Unexpected redeclaration of read-only global variable.'
Source
Thrown at crates/oxc_linter/src/rules/eslint/no_implicit_globals.rs:41
fn global_lexical_binding_diagnostic(kind: &'static str, span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn(format!("Unexpected {kind} declaration in the global scope."))
.with_help("Wrap it in a block or in an IIFE.")
.with_label(span)
}
fn global_variable_leak_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Global variable leak.")
.with_help("Declare the variable if it is intended to be local.")
.with_label(span)
}
fn assignment_to_readonly_global_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Unexpected assignment to read-only global variable.").with_label(span)
}
fn redeclaration_of_readonly_global_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Unexpected redeclaration of read-only global variable.").with_label(span)
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
struct NoImplicitGlobalsConfig {
lexical_bindings: bool,
}
#[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema)]
pub struct NoImplicitGlobals(NoImplicitGlobalsConfig);
declare_oxc_lint!(
/// ### What it does
///
/// Disallows declarations in the global scope, global variable leaks, and
/// writes or redeclarations of read-only globals.
///
/// ### Why is this bad?View on GitHub (pinned to e1e7af627c)
Solutions
- Rename the local declaration (appStatus instead of status).
- Wrap polyfills in an IIFE and assign to globalThis explicitly when overriding is truly intended.
- Give polyfill files a separate lint config where the name is allowed.
Example fix
// before (browser script) var status = 'ready'; // after var appStatus = 'ready';
Defensive patterns
Strategy: validation
Validate before calling
const redeclare = /^\s*(?:var|function)\s+(?:name|status|top|event|length|Promise|fetch)\b/m.test(source);
Prevention
- Avoid top-level names that collide with window/built-in globals (name, status, top, event, Promise).
- Wrap polyfills in IIFEs and assign to globalThis deliberately.
- Namespace app globals (myAppStatus) instead of reusing built-in names.
When it happens
Trigger: function Promise(executor) {...} as a script-tag polyfill override; var status = 'ready'; or var top = document.getElementById('x'); in a browser script (window properties); var event = ...; shadowing the global handler names.
Common situations: Polyfills (Promise, fetch) in script-tag deployments; naming a top-level variable name, length, status, event, or top in browser code; Node examples pasted into browser scripts.
Related errors
- Read-only global '{global_name}' should not be modified.
- Unexpected {kind} declaration in the global scope.
- Global variable leak.
- Unexpected assignment to read-only global variable.
- Import the following Jest functions from `@jest/globals`: {g
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/5c0144e6ef6a1ee1.
Report an issue: GitHub.