oxc-project/oxc · info · OxcDiagnostic

Unexpected `if` as the only statement in a `if` block withou

Error message

Unexpected `if` as the only statement in a `if` block without `else`.

What it means

Diagnostic from the oxlint rule `unicorn/no-lonely-if`. When an `if` block without an `else` contains exactly one statement and that statement is another `if`, the nesting reads like a forgotten case or a half-finished merge. The rule wants the tests joined into a single condition or the guards flattened with early returns. Purely stylistic — the control flow is equivalent.

Source

Thrown at crates/oxc_linter/src/rules/unicorn/no_lonely_if.rs:9

use oxc_ast::AstKind;
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;

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

fn no_lonely_if_diagnostic(if_stmt_span: Span, parent_if_stmt_span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Unexpected `if` as the only statement in a `if` block without `else`.")
        .with_help("Move the inner `if` test to the outer `if` test.")
        .with_labels([if_stmt_span, parent_if_stmt_span])
}

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

declare_oxc_lint!(
    /// ### What it does
    ///
    /// Disallow `if` statements as the only statement in `if` blocks without `else`.
    ///
    /// ### Why is this bad?
    ///
    /// It can be confusing to have an `if` statement without an `else` clause as the only statement in an `if` block.
    ///
    /// ### Examples
    ///

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Merge the conditions: `if (user && user.isActive)` or with optional chaining `if (user?.isActive)`
  2. Prefer early returns/continue to keep guard clauses flat
  3. When the inner test is intentionally a separate documented stage, suppress with `// oxlint-disable-next-line unicorn/no-lonely-if`

Example fix

// before
if (user) {
  if (user.isActive) {
    grant(user);
  }
}

// after
if (user?.isActive) {
  grant(user);
}
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: `if (user) { if (user.isActive) { grant(user); } }` — the inner `if` is the sole statement of the outer `if`'s consequent, and the outer `if` has no `else`. Both spans are labeled in the diagnostic.

Common situations: Guards layered on one refactor at a time; feature flags nested inside conditionals; merge artifacts where a second check got wrapped instead of combined with `&&`.

Related errors


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