oxc-project/oxc · error
Expected a conditional expression and instead saw an assignm
Error message
Expected a conditional expression and instead saw an assignment
What it means
Diagnostic from the oxlint rule `no-cond-assign` (crates/oxc_linter/src/rules/eslint/no_cond_assign.rs). It fires when an assignment expression (`=`, `+=`, ...) is used as the test of an `if`, `while`, `do-while`, or `for(...;;...)` condition or of a ternary. The default option `except-parens` permits assignments only when wrapped in additional parentheses; the `always` option flags every assignment inside a condition, even parenthesized ones. The diagnostic's span is narrowed to just the assignment operator token.
Source
Thrown at crates/oxc_linter/src/rules/eslint/no_cond_assign.rs:18
use oxc_ast::{
AstKind,
ast::{AssignmentExpression, Expression},
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};
use schemars::JsonSchema;
use serde::Deserialize;
use crate::{
AstNode,
context::LintContext,
rule::{DefaultRuleConfig, Rule},
};
fn no_cond_assign_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Expected a conditional expression and instead saw an assignment")
.with_help("Consider wrapping the assignment in additional parentheses")
.with_label(span)
}
#[derive(Debug, Default, Clone, Deserialize)]
pub struct NoCondAssign(NoCondAssignConfig);
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Deserialize, JsonSchema)]
#[serde(rename_all = "kebab-case")]
enum NoCondAssignConfig {
/// Allow assignments in conditional expressions only if they are
/// enclosed in parentheses.
#[default]
ExceptParens,
/// Disallow all assignments in conditional expressions.
Always,
}
View on GitHub (pinned to e1e7af627c)
Solutions
- If it is a typo, change `=` to `===`/`==` in the condition.
- If the assignment-in-condition is intentional, wrap it in extra parentheses: `if ((x = compute())) {...}` (allowed by the default `except-parens` mode).
- Prefer separating the assignment from the test: `x = compute(); if (x) {...}` — clearest under both modes.
- If your team relies on parenthesized condition assignments, ensure the rule is configured as `"no-cond-assign": "error"` or `["error", "except-parens"]`, not `"always"`.
Example fix
// before
if (user.jobTitle = "manager") { /* always truthy; also corrupts jobTitle */ }
// after
if (user.jobTitle === "manager") { }
// intentional assignment case
while ((line = readLine()) !== null) { process(line); } Defensive patterns
Strategy: validation
Validate before calling
// Heuristic pre-check for single-= conditions (oxlint's AST check is authoritative) const suspect = /\b(if|while)\s*\(\s*[\w.$]+\s*(=[^=]|\+=|-=)/.test(src);
Prevention
- Write conditions with explicit comparison operators; never assign in a test.
- Keep the intentional walker idiom double-parenthesized: while ((x = next()) !== null).
- Decide team-wide between except-parens (default) and always, and encode it in .oxlintrc.json.
When it happens
Trigger: Under default config: `if (x = 0) {}`, `while (x += 1) {}`, `for (; x = y; ) {}`, `cond = a ? b : c` where the ternary test is an assignment. Under `always`, additionally forms like `if ((x = 0)) {}` and `if (a || (b = c)) {}` inside the condition's span (assignments in the body still pass).
Common situations: Typo `=` for `===` in conditions (the classic `if (user.jobTitle = "manager")` bug); intentional readline/walker idioms like `while ((line = reader.next()) !== null)` that need the extra parens under default config; switching the config from `except-parens` to `always` and tripping on previously-allowed parenthesized assignments.
Related errors
- '{prop_name}' is not a valid ARIA attribute.
- Unexpected re-assignment of `const` variable {name}.
- Unexpected constant condition
- '{name}' is a function.
- Unexpected assignment to read-only global variable.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/cb3c4fc7452fb990.
Report an issue: GitHub.