oxc-project/oxc · warning · OxcDiagnostic
Error message should be a string.
Error message
Error message should be a string.
What it means
Diagnostic from oxlint's `unicorn/error-message` rule. The message argument is an array literal `[...]` or object literal `{...}` — non-string literals that are almost certainly a mistake, since `Error` stringifies them into useless text like the joined array items. The rule checks only these literal forms at the message position of the built-in error constructors; identifiers, calls, and other expressions are not flagged.
Source
Thrown at crates/oxc_linter/src/rules/unicorn/error_message.rs:27
use crate::{AstNode, context::LintContext, rule::Rule, utils::BUILT_IN_ERRORS};
fn missing_message(ctor_name: &str, span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn(format!("Pass a message to the {ctor_name:1} constructor."))
.with_help(
"A descriptive message makes the error easier to debug when it is caught or logged.",
)
.with_label(span)
}
fn empty_message(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Error message should not be an empty string.")
.with_help("Provide a non-empty string that describes what went wrong.")
.with_label(span)
}
fn not_string(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Error message should be a string.")
.with_help(
"The first argument to an error constructor should be a string describing the error.",
)
.with_label(span)
}
#[derive(Default, Debug, Clone)]
pub struct ErrorMessage;
declare_oxc_lint!(
/// ### What it does
///
/// Enforces providing a `message` when creating built-in `Error` objects to
/// improve readability and debugging.
///
/// ### Why is this bad?
///
/// Throwing an `Error` without a message, like `throw new Error()`, provides no contextView on GitHub (pinned to e1e7af627c)
Solutions
- Join arrays into a single string: `new Error(issues.join(', '))`.
- Serialize objects deliberately: `new Error(JSON.stringify(details))`, or keep details on a custom property and pass a summary string as the message.
- Subclass Error if you need structured payloads instead of forcing them into the message.
Example fix
// before
throw new Error(['code missing', 'host missing']);
// after
throw new Error('Validation failed: ' + ['code missing', 'host missing'].join(', ')); Defensive patterns
Strategy: validation
Prevention
- Pass a single string as the error message; join arrays and stringify objects before constructing the error.
- Carry structured payloads on custom error subclasses instead of the message slot.
- Treat `new Error([...])`/`new Error({...})` as review-blocking smells.
When it happens
Trigger: `throw new Error(['code missing', 'host missing'])` or `throw new ValidationError({ field: 'email' })` where the callee is a global built-in error constructor (for user-defined error classes the rule does not fire).
Common situations: Validation code collecting multiple issues and passing the array directly; refactors where an options object was mistakenly put in the message slot.
Related errors
- Prefer consistent types when spreading a ternary in an array
- Invalid class name, use `{expected}`.
- Missing call to `super()` in constructor.
- The `name` property should be set to `{name}`.
- Pass a message to the {ctor_name:1} constructor.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/a4d13ca2f43f967c.
Report an issue: GitHub.