oxc-project/oxc · info · OxcDiagnostic

Unexpected dangling '_' in '`{name}`'.

Error message

Unexpected dangling '_' in '`{name}`'.

What it means

`no-underscore-dangle` flags identifiers and member expressions with leading or trailing underscores (the "dangling" underscore), e.g. `this._internal`, `name_`. It reports the exact name in the message and suggests the `allow` config. The rule is highly configurable: `allow` (name list), `allowAfterThis`, `allowAfterSuper`, `allowAfterThisConstructor`, `allowInArrayDestructuring` / `allowInObjectDestructuring` (default true), `allowFunctionParams` (default true), `allowInUsingDeclarations`, plus `enforceInClassFields` / `enforceInMethodNames` to require underscores.

Source

Thrown at crates/oxc_linter/src/rules/eslint/no_underscore_dangle.rs:24

    ast::{
        BindingIdentifier, Expression, FunctionType, PrivateFieldExpression, PropertyKey,
        StaticMemberExpression,
    },
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::NodeId;
use oxc_span::Span;

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

fn no_underscore_dangle_diagnostic(span: Span, name: &str) -> OxcDiagnostic {
    OxcDiagnostic::warn(format!("Unexpected dangling '_' in '`{name}`'."))
        .with_help(format!("Remove the dangling '_' or add `{name}` to the 'allow' configuration."))
        .with_label(span)
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
pub struct NoUnderscoreDangleConfig {
    /// Whether to allow dangling underscores in members of the `super` object.
    allow_after_super: bool,
    /// Whether to allow dangling underscores in members of the `this.constructor` object.
    allow_after_this_constructor: bool,
    /// An array of variable names that are allowed to have dangling underscores.
    allow: Vec<String>,
    /// Whether to allow dangling underscores in members of the `this` object.
    allow_after_this: bool,
    /// Whether to allow dangling underscores in variable names assigned by array destructuring.
    allow_in_array_destructuring: bool,
    /// Whether to allow dangling underscores in variable names assigned by object destructuring.

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Rename your own identifier to drop the dangling underscore.
  2. For library members you cannot rename, add the names to `allow` or enable `allowAfterThis` / `allowAfterSuper`.
  3. If the team convention embraces underscore-privates, disable the rule instead of fighting it.

Example fix

// before
class Store {
  _cache = new Map();
  get(key) {
    return this._cache.get(key);
  }
}

// after
class Store {
  #cache = new Map(); // real private field
  get(key) {
    return this.#cache.get(key);
  }
}
Defensive patterns

Strategy: validation

Validate before calling

# CI gate; tune config (allow, allowAfterThis, ...) instead of suppressing case by case
npx oxlint src/ # rules: { "eslint/no-underscore-dangle": ["warn", { "allow": ["_internal"] }] }

Prevention

When it happens

Trigger: Accessing private-by-convention members `obj._foo`, `this._cache`, naming variables `index_` or `_count` — reported unless covered by one of the allow options or listed in `allow`.

Common situations: Calling third-party/library APIs that expose underscore-prefixed methods; teams whose convention actually uses `_` for private fields (then the rule should be off or configured); destructuring `const { _internal } = obj;` after someone disabled the destructuring allowances.

Related errors


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