jax-ml/jax · error · ValueError
Unsatisfiable explicit constraint: {constr.debug_str}
Error message
Unsatisfiable explicit constraint: {constr.debug_str} What it means
After parsing, JAX evaluates the constant difference e1-e2 of a constraint. If both sides are known constants and the constraint is false (e.g. '3 == 4' or '2 >= 5'), it is unsatisfiable and rejected immediately.
Source
Thrown at jax/_src/export/shape_poly.py:1071
if cmp_pos < 0:
raise ValueError("Constraint parsing error: must contain one of '==' or '>=' or '<='")
e1_str = c_str[:cmp_pos]
e1, = _Parser(e1_str, None, repr(e1_str), self).parse()
e2_str = c_str[cmp_pos + 2:]
e2, = _Parser(e2_str, None, repr(e2_str), self).parse()
if cmp == Comparator.GEQ and not is_geq:
e1, e2 = e2, e1
# Compute e1 - e2 before we add to normalization rules
constr = _SymbolicConstraint(debug_str=c_str, cmp=cmp, e1=e1, e2=e2,
diff=e1 - e2)
self._process_explicit_constraint(constr)
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 andView on GitHub (pinned to 1e1c6a8fc0)
Solutions
- Fix the arithmetic or comparator direction so the constant constraint holds
- If the operands were meant to be symbolic, check variable spelling (a typo makes both sides constant)
- Print/inspect the generated constraint strings before constructing the SymbolicScope
Example fix
# before
constraints = ('2 * 2 >= 5',)
# after
constraints = ('2 * 2 <= 5',) # or fix the intended math Defensive patterns
Strategy: validation
Validate before calling
# both sides constant and comparison false -> reject early
for c in constraints:
if well_formed(c) and both_constant(c): assert eval_const_cmp(c) Try / catch
try:
scope = SymbolicScope(constraints)
except ValueError as e:
if 'Unsatisfiable' in str(e): fix_constraint_arithmetic() Prevention
- Double-check comparator direction when writing bounds
- Log generated constraint strings before constructing scopes
When it happens
Trigger: Constraints between constants that contradict: '4 <= 3', '8 == 9', or expressions that constant-fold to a violated comparison, e.g. '2*2 >= 5'.
Common situations: Computed constraint strings where a variable was substituted by a wrong constant; inverted comparison direction by mistake.
Related errors
- The symbolic constraints should be a sequence of strings. Go
- SymbolicScope constraint must be a string: got {repr(c_str)}
- Constraint parsing error: must contain one of '==' or '>=' o
- Invalid equality constraint: {e1} == {e2}. The left-hand-sid
- Found multiple equality constraints with the same left-hand-
AI-assisted analysis of jax-ml/jax@1e1c6a8fc0 (2026-08-27).
Data as JSON: /api/errors/3bc14f8039292dc2.
Report an issue: GitHub.