{"record":{"id":"47f1ad1bca369ea5","repo":"jax-ml/jax","slug":"invalid-equality-constraint-e1-e2-the-lef","errorCode":null,"errorMessage":"Invalid equality constraint: {e1} == {e2}. The left-hand-side must be of the form `term * coefficient`.","messagePattern":"Invalid equality constraint: (.+?) == (.+?)\\. The left-hand-side must be of the form `term \\* coefficient`\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"jax/_src/export/shape_poly.py","lineNumber":1076,"sourceCode":"    e2, = _Parser(e2_str, None, repr(e2_str), self).parse()\n    if cmp == Comparator.GEQ and not is_geq:\n      e1, e2 = e2, e1\n\n    # Compute e1 - e2 before we add to normalization rules\n    constr = _SymbolicConstraint(debug_str=c_str, cmp=cmp, e1=e1, e2=e2,\n                                 diff=e1 - e2)\n    self._process_explicit_constraint(constr)\n\n  def _process_explicit_constraint(self, constr: _SymbolicConstraint):\n    if (diff_const := _DimExpr._to_constant(constr.diff)) is not None:\n      if ((constr.cmp == Comparator.EQ and diff_const != 0) or\n          (constr.cmp == Comparator.GEQ and diff_const < 0)):\n        raise ValueError(f\"Unsatisfiable explicit constraint: {constr.debug_str}\")\n      return\n\n    if constr.cmp == Comparator.EQ:\n      if not isinstance(constr.e1, _DimExpr):\n        raise ValueError(\"Invalid equality constraint: {e1} == {e2}. \"\n                         \"The left-hand-side must be of the form `term * coefficient`.\")\n      (before, before_k), *rest = constr.e1._sorted_terms\n      if rest:\n        raise ValueError(\"Invalid equality constraint: {e1} == {e2}. \"\n                         \"The left-hand-side must be of the form `term * coefficient`.\")\n\n      after = _ensure_poly(constr.e2, \"parse_constraint\", constr.e1.scope)\n      if before in self._normalization_rules:\n        raise NotImplementedError(\n            f\"Found multiple equality constraints with the same left-hand-side: {before}\")\n      self._normalization_rules[before] = (after, before_k)\n      # Look for constraints of the form mod(before_e1, before_k2) * 1 == 0\n      if (before_k == 1 and\n          isinstance(constr.e2, int) and constr.e2 == 0 and\n          (before_f := before.to_factor()) and\n          before_f.operation == _DimFactor.MOD and\n          (before_k2 := _DimExpr._to_constant(before_f.operands[1])) is not None):\n        # Add before_k2*floordiv(before_e1, before_k2) == before_e1","sourceCodeStart":1058,"sourceCodeEnd":1094,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/export/shape_poly.py#L1058-L1094","documentation":"For equality constraints used as normalization rules (solving one variable in terms of others), the left-hand side must be a single term times a coefficient (e.g. 'a * 2 == b'). If the LHS is not a symbolic expression at all (a bare constant), the constraint cannot define a normalization and is rejected.","triggerScenarios":"Constraints like '4 == b', '8 == n*2', or '2 == a' where the LHS contains no dimension variable.","commonSituations":"Writing the constant on the left by habit; constraints intended as range checks mistakenly written with '==' and constant LHS.","solutions":["Put the symbolic term on the left-hand side: 'n * 2 == 8' instead of '8 == n * 2'","If the constraint is a bound, use '>=' or '<=' instead of '=='","Ensure at least one dim variable appears on the LHS"],"exampleFix":"# before\nconstraints = ('8 == n * 2',)\n# after\nconstraints = ('n * 2 == 8',)","handlingStrategy":"validation","validationCode":"for c in eq_constraints:\n    lhs = c.split('==')[0]\n    assert has_dim_var(lhs), f'LHS must contain a variable: {c}'","typeGuard":"def lhs_is_symbolic(c: str) -> bool:\n    return any(ch.isalpha() for ch in c.split('==')[0])","tryCatchPattern":null,"preventionTips":["Put the variable term on the left of every equality","Use >=/<= for pure bounds"],"tags":["jax","shape-polymorphism","constraints","normalization"],"backgroundTag":"invalid-constraint-format","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}