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

  1. If it is a typo, change `=` to `===`/`==` in the condition.
  2. If the assignment-in-condition is intentional, wrap it in extra parentheses: `if ((x = compute())) {...}` (allowed by the default `except-parens` mode).
  3. Prefer separating the assignment from the test: `x = compute(); if (x) {...}` — clearest under both modes.
  4. 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

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


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