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

  1. Rename the local declaration (appStatus instead of status).
  2. Wrap polyfills in an IIFE and assign to globalThis explicitly when overriding is truly intended.
  3. 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

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


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