oxc-project/oxc · warning · OxcDiagnostic

Unreachable code.

Error message

Unreachable code.

What it means

Diagnostic from oxlint's no-unreachable rule (port of ESLint no-unreachable). It fires when statements follow a statement that unconditionally terminates control flow (return, throw, break, continue) because the control-flow-graph helper effective_unreachable_blocks proves those statements can never execute.

Source

Thrown at crates/oxc_linter/src/rules/eslint/no_unreachable.rs:13

use oxc_ast::{AstKind, AstType, ast::VariableDeclarationKind};
use oxc_cfg::{Instruction, InstructionKind};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::NodeId;
use oxc_span::{GetSpan, Span};

use crate::{
    context::ContextHost, context::LintContext, rule::Rule, utils::effective_unreachable_blocks,
};

fn no_unreachable_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Unreachable code.")
        .with_help("Remove the unreachable code or fix the control flow to make it reachable.")
        .with_label(span)
}

/// <https://github.com/eslint/eslint/blob/069aa680c78b8516b9a1b568519f1d01e74fb2a2/lib/rules/no-unreachable.js#L196>
#[derive(Debug, Default, Clone)]
pub struct NoUnreachable;

const NEEDED_NODE_TYPES: &AstTypesBitset = &AstTypesBitset::from_types(&[
    AstType::ReturnStatement,
    AstType::ThrowStatement,
    AstType::BreakStatement,
    AstType::ContinueStatement,
    AstType::WhileStatement,
    AstType::DoWhileStatement,
    AstType::ForStatement,
]);

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Delete the unreachable statements after the terminating statement.
  2. If the code must run, move it above the return/throw/break/continue.
  3. If the terminator was meant to be conditional, fix the control flow so the following code is reachable.
  4. If the dead code is kept intentionally, annotate that line with an oxlint-disable no-unreachable comment.

Example fix

// before
function f(x) {
  return x * 2;
  console.log('never runs');
}
// after
function f(x) {
  return x * 2;
}
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Any statement placed after an unconditional return/throw/break/continue in the same block; code after an infinite loop (while(true){} with no break) or after a call that never returns. The rule registers on Return/Throw/Break/ContinueStatement kinds and checks CFG reachability.

Common situations: Guard clauses added during refactoring leave old code below an early return; statements appended after a throw new Error(...); leftover debug code after return; auto-merged branches placing code after a terminator.

Related errors


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