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
- Merge the conditions: `if (user && user.isActive)` or with optional chaining `if (user?.isActive)`
- Prefer early returns/continue to keep guard clauses flat
- 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
- Combine nested guards into `&&` conditions or early returns as you write them
- Watch for lonely ifs appearing after feature-flag removal
- Remember the rule only fires when the outer if has no else block
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
- Require or disallow "Yoda" conditions
- Expected return with your callback function.
- Do not access a member directly from an await expression.
- Invalid group length in numeric value.
- `VirtualFree` failed during cleanup: {err}
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/f8002dc45b74c3fa.
Report an issue: GitHub.