{"record":{"id":"838538089817d6dc","repo":"oxc-project/oxc","slug":"promise-should-not-be-resolved-multiple-times-pro-838538","errorCode":null,"errorMessage":"Promise should not be resolved multiple times. Promise is potentially resolved on line {line}.","messagePattern":"Promise should not be resolved multiple times\\. Promise is potentially resolved on line (.+?)\\.","errorType":"validation","errorClass":"OxcDiagnostic","httpStatus":null,"severity":"warning","filePath":"crates/oxc_linter/src/rules/promise/no_multiple_resolved.rs","lineNumber":33,"sourceCode":"use oxc_diagnostics::OxcDiagnostic;\nuse oxc_macros::declare_oxc_lint;\nuse oxc_semantic::{Scoping, SymbolId};\nuse oxc_span::Span;\nuse rustc_hash::{FxHashMap, FxHashSet};\n\nuse crate::{\n    AstNode, context::LintContext, rule::Rule, utils::get_promise_constructor_inline_executor,\n};\n\nfn already_resolved_diagnostic(line: usize, span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(format!(\n        \"Promise should not be resolved multiple times. Promise is already resolved on line {line}.\"\n    ))\n    .with_label(span)\n}\n\nfn potentially_already_resolved_diagnostic(line: usize, span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(format!(\"Promise should not be resolved multiple times. Promise is potentially resolved on line {line}.\")).with_label(span)\n}\n\n#[derive(Debug, Default, Clone)]\npub struct NoMultipleResolved;\n\ndeclare_oxc_lint!(\n    /// ### What it does\n    ///\n    /// This rule warns of paths that resolve multiple times in executor functions of Promise constructors.\n    ///\n    /// ### Why is this bad?\n    ///\n    /// Multiple resolve/reject calls:\n    /// - Violate the Promise/A+ specification\n    /// - Have no effect on the Promise's behavior\n    /// - Make the code's intent unclear\n    /// - May indicate logical errors in the implementation\n    ///","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/oxc-project/oxc/blob/36ec0ef2bae567d1a8413ada2fe795f1af1f2785/crates/oxc_linter/src/rules/promise/no_multiple_resolved.rs#L15-L51","documentation":"Diagnostic from the oxlint rule `promise/no-multiple-resolved` (plugin `promise`, category `suspicious`). This is the flow-sensitive variant: the CFG analysis found that at least one (but not all) incoming path to the second `resolve`/`reject` call had already settled the promise, so the promise is 'potentially' already resolved on line N. The 'potentially' wording comes from the ResolvedKind::Potential classification in the rule's dominator-based path analysis. Such calls are no-ops when they are redundant, but indicate a missing guard, `else`, or early `return`.","triggerScenarios":"`if (error) { reject(error) }` followed by an unconditional `resolve(value)` (reject branch may or may not run); a settle inside a nested `if` at any depth with a later unconditional settle; `if (foo) { ... if (bar) reject(e) ... } resolve(v)` where the inner reject only fires on some paths.","commonSituations":"Error-first callback wrappers missing the `else`; guard clauses partially covering paths; refactors that move code below an existing conditional reject; copy-pasted executors where only some branches were updated.","solutions":["Make the branches exclusive: add `else` before the trailing `resolve(value)` or `return` inside the reject branch","Guard the later settle with the inverse condition: `if (!error) resolve(value)`","Delete whichever settle call is unreachable dead code","Replace the wrapper with `util.promisify` or rewrite as an `async` function so there is exactly one settle"],"exampleFix":"// before\nnew Promise((resolve, reject) => {\n  fn((error, value) => {\n    if (error) {\n      reject(error)\n    }\n\n    resolve(value)\n  })\n})\n\n// after\nnew Promise((resolve, reject) => {\n  fn((error, value) => {\n    if (error) {\n      reject(error)\n      return\n    }\n\n    resolve(value)\n  })\n})","handlingStrategy":"validation","validationCode":"# the same rule covers the 'potentially' variant - run it in pre-commit/CI\nnpx oxlint --promise/no-multiple-resolved src/","typeGuard":null,"tryCatchPattern":null,"preventionTips":["After any conditional `reject`, make the next `resolve` exclusive (`else`, `return`, or `if (!error)`)","Run the linter locally before pushing; this variant only appears from path analysis of your edited executor","In code review, check that loops containing settle calls have no settle after the loop","Keep executors small - move the body out so settle calls are trivially auditable"],"tags":["promise","async","lint","control-flow","oxlint"],"backgroundTag":"promise-resolved-multiple-times","analyzedSha":"36ec0ef2bae567d1a8413ada2fe795f1af1f2785","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}