jax-ml/jax · error · ValueError

Brackets are not balanced in rule

Error message

Brackets are not balanced in rule: '{rule}'

What it means

Parse error in the sharding-rule string: after processing all characters a parenthesized group is still open, i.e. there is a '(' without a matching ')'. The parser reports the unbalanced brackets with the full rule for context.

Solutions

  1. Add the missing ')' for every open '('
  2. If generating rules in code, assert rule.count('(') == rule.count(')') before use

Example fix

# before
rule = '(a,b->(a,b)'
# after
rule = '(a,b)->(a,b)'
Defensive patterns

Strategy: validation

Validate before calling

assert rule.count('(') == rule.count(')'), 'unbalanced parentheses in rule'

Type guard

def parens_balanced(rule: str) -> bool:
    d = 0
    for c in rule:
        d += (c == '(') - (c == ')')
        if d < 0: return False
    return d == 0

Prevention

When it happens

Trigger: Rule like '(a,b->(a,b)' where the first compound factor's ')' is missing.

Common situations: Typos from hand-writing long multi-operand rules.

Related errors


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

Appendix: source

Thrown at jax/_src/custom_partitioning_sharding_rule.py:307

        if len(current_compound_dim) <= 1:
          raise ValueError("Brackets should contain at least two factors")
        value.append(CompoundFactor(*current_compound_dim))
        current_compound_dim = None
      elif char == ",":
        all_values.append(ArrayMapping(*value))
        value = []
    elif char == "_" or char.isdigit() or char.isalpha():
      if current_factor is None:
        if str.isdigit(char):
          raise ValueError(f"Factor names have to start with a letter, but got '{char}'")
        current_factor = char
      else:
        current_factor += char
    else:
      raise ValueError(f"Unknown character '{char}'")

  if current_compound_dim is not None:
    raise ValueError(f"Brackets are not balanced in rule: '{rule}'")
  if current_factor is not None:
    add_factor(current_factor)
  all_values.append(ArrayMapping(*value))

  return tuple(all_values)

def str_to_sdy_sharding_rule(rule: str, *,
                             reduction_factors: tuple[str, ...] = (),
                             need_replication_factors: tuple[str, ...] = (),
                             permutation_factors: tuple[str, ...] = (),
                             **factor_sizes: int) -> SdyShardingRule:
  """Constructs a SdyShardingRule object from the Einsum notation like string.

  This is done by verifying that the input Einsum notation like string and
  with optional special factors and factor sizes represents a valid sharding
  rule and converting it to an internal representation.

  Args:

View on GitHub (pinned to 1e1c6a8fc0)