oxc-project/oxc · warning · OxcDiagnostic

Expected throw instead of Promise.reject

Error message

Expected throw instead of Promise.reject

What it means

Diagnostic from the oxlint rule `promise/no-return-wrap` (plugin `promise`) for the Reject variant. It flags `return Promise.reject(e)` inside a promise handler. The idiomatic equivalent is `throw e`: throwing propagates through the chain to the next `catch` with better stack information in some engines, while a returned rejected promise is a second-class way to signal failure from a handler. Setting `{ "allowReject": true }` in the rule config makes returning `Promise.reject` legal (the rule's doc comment documents exactly this escape hatch).

Source

Thrown at crates/oxc_linter/src/rules/promise/no_return_wrap.rs:32

use oxc_ast_visit::VisitJs;
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use schemars::JsonSchema;
use serde::Deserialize;

fn no_return_wrap_diagnostic(span: Span, issue: &ReturnWrapper) -> OxcDiagnostic {
    let warn_msg = match issue {
        ReturnWrapper::Resolve => "Avoid wrapping return values in Promise.resolve",
        ReturnWrapper::Reject => "Expected throw instead of Promise.reject",
    };

    let help_msg = match issue {
        ReturnWrapper::Resolve => "Return the value being passed into Promise.resolve instead",
        ReturnWrapper::Reject => "Throw the value being passed into Promise.reject instead",
    };

    OxcDiagnostic::warn(warn_msg).with_help(help_msg).with_label(span)
}

#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
pub struct NoReturnWrap {
    /// `allowReject` allows returning `Promise.reject` inside a promise handler.
    ///
    /// With `allowReject` set to `true` the following are examples of correct code:
    ///
    /// ```js
    /// myPromise().then(
    ///   function() {
    ///     return Promise.reject(0)
    /// })
    /// ```
    ///
    /// ```js
    /// myPromise().then().catch(() => Promise.reject("err"))

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Replace with `throw`: `throw new Error(...)` inside the handler
  2. If the team convention is returning `Promise.reject`, set `{ "allowReject": true }` in the rule configuration
  3. Rethrow the original error with context: `throw new Error('context', { cause: err })`

Example fix

// before
promise.catch(err => {
  return Promise.reject(new Error('wrapped: ' + err.message))
})

// after
promise.catch(err => {
  throw new Error('wrapped: ' + err.message)
})
Defensive patterns

Strategy: validation

Validate before calling

npx oxlint --promise/no-return-wrap src/
# team convention prefers returning Promise.reject? permit it:
#   { "rules": { "promise/no-return-wrap": ["error", { "allowReject": true }] } }

Prevention

When it happens

Trigger: `promise.catch(err => { return Promise.reject(new Error('wrapped')) })`; `then(val => { if (!val) return Promise.reject(new Error('missing')) })` with default `allowReject: false`.

Common situations: Error-mapping code inside `catch` handlers; guard clauses written before the team standardized on `throw`; codebases that deliberately prefer `Promise.reject` and need the `allowReject` config.

Related errors


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