{"record":{"id":"d40fceaac152b60b","repo":"oxc-project/oxc","slug":"invalid-loop-its-body-allows-only-one-iteration","errorCode":null,"errorMessage":"Invalid loop. Its body allows only one iteration.","messagePattern":"Invalid loop\\. Its body allows only one iteration\\.","errorType":"validation","errorClass":"OxcDiagnostic","httpStatus":null,"severity":"warning","filePath":"crates/oxc_linter/src/rules/eslint/no_unreachable_loop.rs","lineNumber":30,"sourceCode":"};\nuse oxc_diagnostics::OxcDiagnostic;\nuse oxc_ecmascript::{\n    GlobalContext,\n    side_effects::{MayHaveSideEffects, MayHaveSideEffectsContext, PropertyReadSideEffects},\n};\nuse oxc_macros::declare_oxc_lint;\nuse oxc_semantic::{IsGlobalReference, NodeId};\nuse oxc_span::{GetSpan, Span};\n\nuse crate::{\n    AstNode,\n    context::LintContext,\n    rule::{DefaultRuleConfig, Rule},\n    utils::effective_unreachable_blocks,\n};\n\nfn no_unreachable_loop_diagnostic(span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(\"Invalid loop. Its body allows only one iteration.\")\n        .with_help(\"Remove the loop or make at least one path continue to the next iteration.\")\n        .with_label(span)\n}\n\n#[derive(Debug, Default, Clone, Deserialize, JsonSchema)]\n#[serde(rename_all = \"camelCase\", default, deny_unknown_fields)]\nstruct NoUnreachableLoopConfig {\n    ignore: Vec<LoopType>,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, JsonSchema)]\nenum LoopType {\n    #[serde(rename = \"WhileStatement\")]\n    While,\n    #[serde(rename = \"DoWhileStatement\")]\n    DoWhile,\n    #[serde(rename = \"ForStatement\")]\n    For,","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/oxc-project/oxc/blob/e1e7af627c8843ab64044ed466b128fcc21a035b/crates/oxc_linter/src/rules/eslint/no_unreachable_loop.rs#L12-L48","documentation":"Diagnostic from oxlint's no-unreachable-loop rule. It reports loops whose body always exits (break/return/throw) on every path of the first iteration, so the loop can never complete a second iteration; the loop construct is pointless or the unconditional exit is a bug. It uses the shared CFG helper effective_unreachable_blocks.","triggerScenarios":"for (const x of xs) { break; }, while (cond) { return; }, loop bodies that unconditionally throw, or a labeled break that always fires on the first pass.","commonSituations":"A conditional if (x) break; is refactored into an unconditional break; a debugging break is left in; a loop is kept as a scoping wrapper after the body became single-pass; generated code wraps single-item iteration.","solutions":["Remove the loop wrapper and keep the body once if single-pass behavior is intended.","Make the break/return/throw conditional so at least one path continues to the next iteration.","Remove the stray break/return left over from debugging.","Add the intentional loop kind to the rule's ignore option (e.g. \"WhileLoop\", \"ForOfLoop\", \"ForLoop\", \"ForInLoop\", \"DoWhileLoop\")."],"exampleFix":"// before\nfor (const item of items) {\n  handle(item);\n  break;\n}\n// after\nfor (const item of items) {\n  if (!shouldHandle(item)) break;\n  handle(item);\n}","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer array methods (map/forEach/every) over loops with manual breaks to make single-pass intent obvious.","Re-read loop bodies after changing conditional guards to unconditional exits.","List intentional single-iteration loops in the rule's ignore option instead of inline disables."],"tags":["eslint","oxlint","loops","control-flow","dead-code"],"backgroundTag":"unreachable-loop","analyzedSha":"e1e7af627c8843ab64044ed466b128fcc21a035b","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}