jax-ml/jax · error · ValueError

SymbolicScope constraint must be a string: got {repr(c_str)}

Error message

SymbolicScope constraint must be a string: got {repr(c_str)}

What it means

Each explicit symbolic constraint must be an individual string like 'a*2 == b'. This error fires when a non-string element (int, tuple, None) ends up in the constraints sequence during parsing.

Source

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

    for c_str in constraints_str:
      self._parse_and_process_explicit_constraint(c_str)
      self._bounds_cache.clear()
    self._initialized = True

  def __str__(self) -> str:
    extras = []
    if self._explicit_constraints:
      extras.append(" with constraints:")
      for constr in self._explicit_constraints:
        extras.append(f"  {constr.debug_str}")
    loc = source_info_util._summarize_frame(self._location_frame) if self._location_frame else "unknown"
    return f"{id(self)} created at {loc}" + "\n".join(extras)
  __repr__ = __str__

  def _parse_and_process_explicit_constraint(self, c_str: str):
    if not isinstance(c_str, str):
      raise ValueError(
          f"SymbolicScope constraint must be a string: got {repr(c_str)}")
    cmp_pos, cmp, is_geq = c_str.find("=="), Comparator.EQ, True
    if cmp_pos < 0:
      cmp_pos, cmp, is_geq = c_str.find(">="), Comparator.GEQ, True
      if cmp_pos < 0:
        cmp_pos, cmp, is_geq = c_str.find("<="), Comparator.GEQ, False
      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)

View on GitHub (pinned to 1e1c6a8fc0)

Solutions

  1. Flatten/convert every constraint to a single formatted string before constructing the scope
  2. Add an assert all(isinstance(c, str) for c in constraints) before the call
  3. Fix the generator expression that produced non-string entries

Example fix

# before
constraints = [('n', '>=', 4)]
# after
constraints = [f'{a} {op} {b}' for a, op, b in [('n', '>=', 4)]]
Defensive patterns

Strategy: validation

Validate before calling

assert all(isinstance(c, str) for c in constraints), constraints

Type guard

def all_str_constraints(cs) -> bool:
    return all(isinstance(c, str) for c in cs)

Prevention

When it happens

Trigger: SymbolicScope([None]), constraints=[('n','>=',4)] (pre-parsed tuples), or dynamically built constraint lists that accidentally include non-string entries.

Common situations: Programmatically assembling constraints where one branch appends a tuple or an f-string's arguments instead of the f-string result.

Related errors


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