oxc-project/oxc · error · OxcDiagnostic

Expected an error object to be thrown

Error message

Expected an error object to be thrown

What it means

`no-throw-literal` reports `throw` statements whose operand is a literal or non-Error value — strings, numbers, booleans, objects, arrays, `null`. Only the `is_undef` case gets the separate "Do not throw undefined" message; this is the general variant. Non-Error throws lose the stack trace and `message`/`name` structure that catch sites and error reporters (Sentry, unhandledRejection handlers) expect, and they crash `catch (e) { e.message }` code.

Source

Thrown at crates/oxc_linter/src/rules/eslint/no_throw_literal.rs:12

use oxc_ast::{AstKind, ast::Expression};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};

use crate::{AstNode, ast_util::could_be_error, context::LintContext, rule::Rule};

fn no_throw_literal_diagnostic(span: Span, is_undef: bool) -> OxcDiagnostic {
    let message =
        if is_undef { "Do not throw undefined" } else { "Expected an error object to be thrown" };

    OxcDiagnostic::warn(message)
        .with_help("Throwing literals or non-Error objects is not recommended. Use an Error object instead.")
        .with_label(span)
}

#[derive(Debug, Default, Clone)]
pub struct NoThrowLiteral;

declare_oxc_lint!(
    /// ### What it does
    ///
    /// Disallows throwing literals or non-Error objects as exceptions.
    ///
    /// ::: warning
    /// This rule has been deprecated, please instead use [typescript/only-throw-error](https://oxc.rs/docs/guide/usage/linter/rules/typescript/only-throw-error.html).
    /// The typescript rule is more reliable than the Javascript version, as it has less false positive, and can catch more cases.
    /// :::
    ///
    /// ### Why is this bad?

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Wrap the value in an Error: `throw new Error('not found');`.
  2. For typed errors, subclass Error and set `name`, or use a cause: `throw new Error('wrap', { cause: original })`.
  3. Search the codebase for existing literals: `rg "throw\\s+['\"0-9{]" src/` and fix each.

Example fix

// before
function load(id) {
  if (!id) throw 'missing id';
}

// after
function load(id) {
  if (!id) throw new Error('missing id');
}
Defensive patterns

Strategy: type-guard

Validate before calling

// guard the value before throwing
function toError(value: unknown): Error {
  return value instanceof Error ? value : new Error(String(value));
}

Type guard

function isError(value: unknown): value is Error {
  return value instanceof Error;
}

Try / catch

try {
  risky();
} catch (e) {
  throw e instanceof Error ? e : new Error(String(e)); // normalize at boundaries
}

Prevention

When it happens

Trigger: `throw 'not found';`, `throw 404;`, `throw { code: 'X' };` — any ThrowStatement whose expression is not an Error construction; the helper `could_be_error` filters values that can be statically proven to be Errors.

Common situations: Older codebases predating Error-as-convention; throwing plain response/error codes in API layers; refactoring promise chains where `reject('timeout')` style strings migrate into `throw`.

Related errors


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