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
- Use startsWith/endsWith for prefix/suffix intent: name.startsWith('Dr')
- Compare against the single character actually accessed: name.charAt(0) === 'D'
- 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
- Use startsWith/endsWith for any prefix/suffix check instead of indexing single characters
- When reviewing charAt/[0] comparisons, eyeball the literal's length — more than one character means dead code
- Cover flagged branches with tests; always-false conditions hide as silently skipped code that tests written by the same author also skip
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Bad comparison sequence
- This comparison will always evaluate to {evaluates_to}
- Math.min and Math.max combination leads to constant result
- Unexpected object literal comparison.
- Unexpected array literal comparison.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/4b38b2f5d3df7e06.
Report an issue: GitHub.