oxc-project/oxc · warning
Do not assign to the exception parameter.
Error message
Do not assign to the exception parameter.
What it means
This diagnostic comes from the `no_ex_assign` rule in oxlint. It reports an assignment to the exception parameter of a `catch` block. After the assignment, the original error object is lost, and no other path leads to it. The rule collects the bound names of the catch parameter with `BoundNames`, so destructured names count too, and reports writes to them.
Source
Thrown at crates/oxc_linter/src/rules/eslint/no_ex_assign.rs:11
use oxc_ast::AstKind;
use oxc_diagnostics::OxcDiagnostic;
use oxc_ecmascript::BoundNames;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::AstNode;
use oxc_span::Span;
use crate::{context::LintContext, rule::Rule};
fn no_ex_assign_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Do not assign to the exception parameter.")
.with_help("Remove the assignment to the exception parameter, or refactor the code to use a different variable.")
.with_note("If code in a catch block assigns a value to the exception parameter, it becomes impossible to refer to the error. Since there is no alternative way to access to this data, assignment of the parameter is absolutely destructive.")
.with_label(span.label("this assignment destroys access to the caught exception"))
}
#[derive(Debug, Default, Clone)]
pub struct NoExAssign;
declare_oxc_lint!(
/// ### What it does
///
/// Disallow reassigning exceptions in catch clauses.
///
/// ### Why is this bad?
///
/// If a catch clause in a try statement accidentally
/// (or purposely) assigns another value to the exception parameter,
/// it is impossible to refer to the error from that point on.View on GitHub (pinned to e1e7af627c)
Solutions
- Use a new variable: `const wrapped = new Error('context'); wrapped.cause = e;`.
- Rethrow with cause: `throw new Error('context', { cause: e });`.
- Suppress only when the value is provably unused after the write: `// oxlint-disable-next-line no-ex-assign`.
Example fix
// before
try {
parse(raw);
} catch (e) {
e = new Error('parse failed');
throw e;
}
// after
try {
parse(raw);
} catch (e) {
throw new Error('parse failed', { cause: e });
} Defensive patterns
Strategy: validation
Validate before calling
// warn on writes to a catch parameter (simple text heuristic)
if (/catch\s*\(\s*(?:[A-Za-z_$][\w$]*|\{[^}]*\})\s*\)[\s\S]{0,120}?\b[A-Za-z_$][\w$]*\s*=(?!=)/.test(src)) {
console.warn('possible assignment to catch parameter');
} Prevention
- Treat the catch parameter as read-only.
- Wrap errors with a `cause` chain; never overwrite the original.
- Destructure only the fields you read, never write to them.
When it happens
Trigger: Inside a catch block: `catch (e) { e = new Error('wrapped'); }`, the destructured form `catch ({ message }) { message = 'x'; }`, or a compound write such as `e += info`. The report labels the assignment span.
Common situations: A developer tries to normalize or wrap the caught error in place. Old patterns reuse the catch variable as a scratch variable. A rename refactor makes the catch parameter collide with a nearby name by habit.
Related errors
- Unexpected empty block statements
- `debugger` statement is not allowed
- Variables should not be deleted
- A regular expression literal can be confused with '/='.
- Duplicate class member: {member_name:?}
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/95469da428d9a70f.
Report an issue: GitHub.