oxc-project/oxc · error · OxcDiagnostic

Invalid character comparison

Error message

Invalid character comparison

What it means

Diagnostic from oxlint rule oxc/bad-char-at-comparison (correctness category). Character access — str.charAt(i), str[i] — returns a string of length at most 1 (or ''), so comparing that result for equality with a string literal longer than one character is provably always false; the guarded branch is dead code that never runs and never fails loudly. The diagnostic carries two labels: where the single character is accessed, and where it is compared against a literal of the stated length.

Source

Thrown at crates/oxc_linter/src/rules/oxc/bad_char_at_comparison.rs:19

use oxc_ast::{
    AstKind,
    ast::{BinaryExpression, Expression, TSType, VariableDeclarator},
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};

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

fn bad_char_at_comparison_diagnostic(
    character_access: Span,
    compared_string: Span,
    len: usize,
) -> OxcDiagnostic {
    OxcDiagnostic::warn("Invalid character comparison")
        .with_help("Character access returns a string of length at most 1. If the return value is compared with a string of length greater than 1, the comparison will always be false.")
        .with_labels([
            character_access.label("A single character is accessed here"),
            compared_string.label(format!("And compared with a string of length {len} here")),
        ])
}

#[derive(Debug, Default, Clone)]
pub struct BadCharAtComparison;

declare_oxc_lint!(
    /// ### What it does
    ///
    /// This rule warns when a character accessed with `charAt`, `at`, or bracket notation is
    /// compared with a string of length greater than 1.
    ///
    /// ### Why is this bad?
    ///

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Use startsWith/endsWith for prefix/suffix intent: name.startsWith('Dr')
  2. Compare against the single character actually accessed: name.charAt(0) === 'D'
  3. For substring containment use includes() or slice() comparisons instead of char access

Example fix

// before
if (mimeType.charAt(0) === 'im') { // always false: charAt returns 1 char
  renderImage();
}

// after
if (mimeType.startsWith('im')) {
  renderImage();
}
Defensive patterns

Strategy: validation

Validate before calling

// .oxlintrc.json
"rules": { "oxc/bad-char-at-comparison": "error" }

npx oxlint -c .oxlintrc.json --deny-warning .

Prevention

When it happens

Trigger: An equality comparison between a character-access expression (charAt / bracket indexing on a string) and a string literal whose length is greater than 1 — the diagnostic formats that length into the second label. Canonical trigger: if (name.charAt(0) === 'Dr') { ... } — the condition can never be true, so the block is unreachable.

Common situations: Prefix/suffix checks on titles ('Dr', 'Sir'), currency symbols, mime types, or file extensions written as equality by developers porting instincts from languages where single-char and string comparisons unify; code that passes tests written against the same wrong assumption — the branch silently never executes.

Understand the failure class

Related errors


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