oxc-project/oxc · warning · OxcDiagnostic

`{name}` is never reassigned.

Error message

`{name}` is never reassigned.

What it means

Diagnostic from the oxlint `prefer-const` rule. It fires for a `let` (or `var`) binding that is assigned exactly once at declaration and never reassigned; the message names the binding and suggests `const` (prefer_const.rs:20-24). Destructuring behavior is controlled by the `destructuring` option and read-before-assign cases by `ignoreReadBeforeAssign` (shown in the config struct in the same file).

Source

Thrown at crates/oxc_linter/src/rules/eslint/prefer_const.rs:20

    AssignmentTarget, AssignmentTargetMaybeDefault, AssignmentTargetProperty, VariableDeclaration,
};
use oxc_ast::{AstKind, ast::VariableDeclarationKind};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::SymbolId;
use oxc_span::{GetSpan, Span};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::{
    AstNode,
    context::LintContext,
    fixer::{RuleFix, RuleFixer},
    rule::{DefaultRuleConfig, Rule},
};

fn prefer_const_diagnostic(name: &str, span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn(format!("`{name}` is never reassigned."))
        .with_help("Use `const` instead.")
        .with_label(span)
}

#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
struct PreferConstConfig {
    /// Configures how destructuring assignments are handled.
    destructuring: Destructuring,
    /// If `true`, the rule will not report variables that are read before their initial assignment.
    /// This is mainly useful for preventing conflicts with the `typescript/no-use-before-define` rule.
    ignore_read_before_assign: bool,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
enum Destructuring {
    /// Warn if any of the variables in a destructuring assignment should be `const`.

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Change `let` to `const` for the flagged binding (auto-fixable with `oxlint --fix`).
  2. If the variable is conditionally reassigned later, restructure so the reassignment is visible to the linter or keep `let` and justify it.
  3. Adjust `destructuring` option ("any" vs "all") if destructured bindings are reported unexpectedly.
  4. Inline-disable for interop patterns (e.g. reassigning a binding from a hot-reload shim).

Example fix

// before
let answer = 42;
console.log(answer);

// after
const answer = 42;
console.log(answer);
Defensive patterns

Strategy: validation

Validate before calling

// .oxlintrc.json — align destructuring policy with your codebase
{ "rules": { "prefer-const": ["warn", { "destructuring": "all", "ignoreReadBeforeAssign": false }] } }

Prevention

When it happens

Trigger: Enable `prefer-const` (part of the correctness-ish default presets in most configs) and write `let x = 1;` where `x` is never reassigned. Also fires for `for (let i of arr)` when `i` is not reassigned inside the loop, and in destructuring per the `destructuring: "any" | "all"` option.

Common situations: Developers typing `let` out of habit for every binding; code migrated from older ES5 var-based style; loops and imports fixed to const during cleanup; `let` inside `try` blocks reassigned only on some paths being misjudged (true reassigned cases are correctly skipped).

Related errors


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