jax-ml/jax · error · NotImplementedError

Found multiple equality constraints with the same left-hand-

Error message

Found multiple equality constraints with the same left-hand-side: {before}

What it means

Equality constraints act as normalization rules keyed by their left-hand-side term. Two constraints with the same LHS term (e.g. 'a == b' and 'a == c') would give contradictory definitions, which is not yet supported, hence NotImplementedError.

Source

Thrown at jax/_src/export/shape_poly.py:1085

  def _process_explicit_constraint(self, constr: _SymbolicConstraint):
    if (diff_const := _DimExpr._to_constant(constr.diff)) is not None:
      if ((constr.cmp == Comparator.EQ and diff_const != 0) or
          (constr.cmp == Comparator.GEQ and diff_const < 0)):
        raise ValueError(f"Unsatisfiable explicit constraint: {constr.debug_str}")
      return

    if constr.cmp == Comparator.EQ:
      if not isinstance(constr.e1, _DimExpr):
        raise ValueError("Invalid equality constraint: {e1} == {e2}. "
                         "The left-hand-side must be of the form `term * coefficient`.")
      (before, before_k), *rest = constr.e1._sorted_terms
      if rest:
        raise ValueError("Invalid equality constraint: {e1} == {e2}. "
                         "The left-hand-side must be of the form `term * coefficient`.")

      after = _ensure_poly(constr.e2, "parse_constraint", constr.e1.scope)
      if before in self._normalization_rules:
        raise NotImplementedError(
            f"Found multiple equality constraints with the same left-hand-side: {before}")
      self._normalization_rules[before] = (after, before_k)
      # Look for constraints of the form mod(before_e1, before_k2) * 1 == 0
      if (before_k == 1 and
          isinstance(constr.e2, int) and constr.e2 == 0 and
          (before_f := before.to_factor()) and
          before_f.operation == _DimFactor.MOD and
          (before_k2 := _DimExpr._to_constant(before_f.operands[1])) is not None):
        # Add before_k2*floordiv(before_e1, before_k2) == before_e1
        k_times_floordiv = _DimExpr._from_term(
            _DimTerm.from_operation(
                _DimFactor.FLOORDIV, *before_f.operands, scope=constr.e1.scope),
            before_k2, scope=constr.e1.scope)
        before_e1 = before_f.operands[0]
        self._process_explicit_constraint(
            _SymbolicConstraint(cmp=Comparator.EQ,
                                e1=k_times_floordiv, e2=before_e1,
                                diff=k_times_floordiv - before_e1,

View on GitHub (pinned to 1e1c6a8fc0)

Solutions

  1. Express one variable in terms of the other instead of repeating the LHS: keep 'a == b' and write 'b == c' (or substitute)
  2. Remove the duplicate equality
  3. Restructure so each symbolic variable is defined by exactly one equality constraint

Example fix

# before
constraints = ('a == b', 'a == c')
# after
constraints = ('a == b', 'b == c')
Defensive patterns

Strategy: validation

Validate before calling

lhs_terms = [normalized_lhs(c) for c in eq_constraints]
assert len(lhs_terms) == len(set(lhs_terms)), 'duplicate LHS in equality constraints'

Try / catch

try:
    scope.add_constraint(c)
except NotImplementedError as e:
    if 'same left-hand-side' in str(e): rewrite_via_chain(c)

Prevention

When it happens

Trigger: Adding constraints 'a*2 == b' and 'a*2 == c' (same normalized LHS term) to one SymbolicScope, including when the second is added later via scope.add_constraint.

Common situations: Dynamically accumulated constraints from multiple modules colliding on the same variable; refactoring that duplicates an existing equality.

Related errors


AI-assisted analysis of jax-ml/jax@1e1c6a8fc0 (2026-08-27). Data as JSON: /api/errors/ad06dfa8cc1035ca. Report an issue: GitHub.