{"record":{"id":"9572a57ee029a5b8","repo":"jax-ml/jax","slug":"brackets-are-not-balanced-in-rule-rule","errorCode":null,"errorMessage":"Brackets are not balanced in rule: '{rule}'","messagePattern":"Brackets are not balanced in rule: '(.+?)'","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"jax/_src/custom_partitioning_sharding_rule.py","lineNumber":307,"sourceCode":"        if len(current_compound_dim) <= 1:\n          raise ValueError(\"Brackets should contain at least two factors\")\n        value.append(CompoundFactor(*current_compound_dim))\n        current_compound_dim = None\n      elif char == \",\":\n        all_values.append(ArrayMapping(*value))\n        value = []\n    elif char == \"_\" or char.isdigit() or char.isalpha():\n      if current_factor is None:\n        if str.isdigit(char):\n          raise ValueError(f\"Factor names have to start with a letter, but got '{char}'\")\n        current_factor = char\n      else:\n        current_factor += char\n    else:\n      raise ValueError(f\"Unknown character '{char}'\")\n\n  if current_compound_dim is not None:\n    raise ValueError(f\"Brackets are not balanced in rule: '{rule}'\")\n  if current_factor is not None:\n    add_factor(current_factor)\n  all_values.append(ArrayMapping(*value))\n\n  return tuple(all_values)\n\ndef str_to_sdy_sharding_rule(rule: str, *,\n                             reduction_factors: tuple[str, ...] = (),\n                             need_replication_factors: tuple[str, ...] = (),\n                             permutation_factors: tuple[str, ...] = (),\n                             **factor_sizes: int) -> SdyShardingRule:\n  \"\"\"Constructs a SdyShardingRule object from the Einsum notation like string.\n\n  This is done by verifying that the input Einsum notation like string and\n  with optional special factors and factor sizes represents a valid sharding\n  rule and converting it to an internal representation.\n\n  Args:","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/custom_partitioning_sharding_rule.py#L289-L325","documentation":"After parsing an entire operand/result side, an open compound factor (current_compound_dim is not None) was never closed. The parser requires all '(' to be matched before the end of the expression.","triggerScenarios":"Rule like '(a,b->(a,b)' where the first compound factor's ')' is missing.","commonSituations":"Typos from hand-writing long multi-operand rules.","solutions":["Add the missing ')' for every open '('","If generating rules in code, assert rule.count('(') == rule.count(')') before use"],"exampleFix":"# before\nrule = '(a,b->(a,b)'\n# after\nrule = '(a,b)->(a,b)'","handlingStrategy":"validation","validationCode":"assert rule.count('(') == rule.count(')'), 'unbalanced parentheses in rule'","typeGuard":"def parens_balanced(rule: str) -> bool:\n    d = 0\n    for c in rule:\n        d += (c == '(') - (c == ')')\n        if d < 0: return False\n    return d == 0","tryCatchPattern":null,"preventionTips":["Count-assert parens in tests that build rule strings"],"tags":["jax","sharding","unbalanced-parens","rule-syntax"],"backgroundTag":"unbalanced-delimiters","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}