oxc-project/oxc · warning · OxcDiagnostic
'{name}' is already declared in the upper scope.
Error message
'{name}' is already declared in the upper scope. What it means
Diagnostic from oxlint's `no-shadow` rule. It fires when an inner scope declares a binding with the same name as one visible in an outer scope, making the outer binding unreachable inside. Labels point at both declarations; for TypeScript enum members an extra note explains that member initializers resolve inside the enum scope.
Source
Thrown at crates/oxc_linter/src/rules/eslint/no_shadow/mod.rs:37
node::NodeId,
symbol::{SymbolFlags, SymbolId},
};
use crate::{
context::LintContext,
rule::{DefaultRuleConfig, Rule},
};
pub use options::{HoistOption, NoShadowConfig};
pub fn no_shadow_diagnostic(
span: Span,
name: &str,
shadowed_span: Span,
is_enum_member: bool,
) -> OxcDiagnostic {
let diagnostic =
OxcDiagnostic::warn(format!("'{name}' is already declared in the upper scope."))
.with_help(format!(
"Consider renaming '{name}' to avoid shadowing the variable from the outer scope."
))
.with_labels([
span.label(format!("'{name}' is declared here")),
shadowed_span.label("shadowed declaration is here"),
]);
if is_enum_member {
diagnostic.with_note(format!(
"Enum members are added to the enum scope, so references to '{name}' in enum member initializers resolve to this member instead of the declaration in the upper scope."
))
} else {
diagnostic
}
}
pub fn no_shadow_global_diagnostic(span: Span, name: &str) -> OxcDiagnostic {View on GitHub (pinned to e1e7af627c)
Solutions
- Rename the inner binding to something specific (`userId` instead of `id`).
- Rename the outer variable if the inner name is the clearer one.
- Adjust `hoist` if function declarations declared after use are being flagged unexpectedly.
- Suppress with an `oxlint-ignore no-shadow` comment for intentional shadowing (e.g. minified-style code).
Example fix
// before
let items = [];
function sync() {
for (let items of groups) { use(items); }
}
// after
let items = [];
function sync() {
for (let group of groups) { use(group); }
} Defensive patterns
Strategy: validation
Validate before calling
// Identify names declared in nested function scopes that match outer declarations
function shadowedNames(src) {
const outer = new Set([...src.matchAll(/(?:let|const|var)\s+([A-Za-z_$][\w$]*)/g)].map(m => m[1]));
const inner = [...src.matchAll(/function\s*\w*\s*\([^)]*\)|=>|\bcatch\s*\(/g)];
// refine with a real parser for production use; heuristic for quick checks
return inner.length && [...outer];
} Prevention
- Give loop/callback variables role-specific names (`userId`, not `id`) so they never collide with outer scope.
- Rename `catch (error)` bindings that shadow an outer `error`.
- Tune `hoist` (`functions`/`all`/`never`) in the rule config so intended patterns are not flagged.
When it happens
Trigger: `let x = 1; function f() { let x = 2; }`; callback params reusing outer names (`items.map(item => ...)` with an outer `item`); TS `enum E { A = B }` where `B` is an outer binding that members shadow. The `hoist` option (`functions`/`all`/`never`) and `builtinGlobals` tune what counts as shadowed.
Common situations: Nested callbacks over similarly-named data; catch blocks declaring `error` when an outer `error` exists; strict codebases enabling no-shadow in pedantic configs after an upgrade.
Related errors
- '{name}' is already defined.
- Unexpected var, use let or const instead.
- Variable declarations should be sorted
- All 'var' declarations must be at the top of the function sc
- encountered allocation error
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/2be80db64a679aa0.
Report an issue: GitHub.