jax-ml/jax · error · ValueError
Unmatched parenthesis in {s!r}
Error message
Unmatched parenthesis in {s!r} What it means
einshape (used by pallas's jax._src.pallas.einshape) parses each side of an einsum-like reshape equation. When an opening parenthesis has no matching ')' anywhere later in the string, _parse_side raises ValueError 'Unmatched parenthesis'. Grouping parentheses like '(ab)c' declare merged/split dimensions and must be balanced.
Source
Thrown at jax/_src/pallas/einshape.py:144
"(ab)c" -> [['a', 'b'], ['c']]
Args:
s: One side of an einshape equation string.
Returns:
A list of lists of characters, where each inner list represents a group of
dimensions.
"""
# Remove spaces
s = s.replace(" ", "")
groups = []
i = 0
while i < len(s):
if s[i] == "(":
# Start of a group
j = s.find(")", i)
if j == -1:
raise ValueError(f"Unmatched parenthesis in {s!r}")
group = list(s[i + 1 : j])
groups.append(group)
i = j + 1
elif s[i] == ")":
raise ValueError(f"Unmatched parenthesis in {s!r}")
else:
# distinct dimension
groups.append([s[i]])
i += 1
return groups
def _parse_equation(equation: str) -> tuple[list[list[str]], list[list[str]]]:
"""Parses an einshape equation."""
if equation.count("->") != 1:
raise ValueError("Equation must contain exactly one '->'")
lhs_str, rhs_str = equation.split("->")
return _parse_side(lhs_str), _parse_side(rhs_str)View on GitHub (pinned to 1e1c6a8fc0)
Solutions
- Balance the parentheses: every '(' needs a matching ')' on the same side of the equation, e.g. 'a(bc) -> abc'
- Programmatically validate with s.count('(') == s.count(')') before calling einshape
- Review einshape docs: parentheses denote dimension groups whose sizes multiply; they cannot span the '->'
Example fix
# before
transforms = get_einshape_transforms('a(b -> ab', x.shape) # unmatched '('
# after
transforms = get_einshape_transforms('a(b) -> ab', x.shape) Defensive patterns
Strategy: validation
Validate before calling
def eq_side_ok(side: str) -> bool:
depth = 0
for ch in side:
if ch == '(':
depth += 1
elif ch == ')':
depth -= 1
if depth < 0:
return False
return depth == 0 Type guard
null
Try / catch
try:
t = get_einshape_transforms(eq, shape)
except ValueError as e:
if 'Unmatched parenthesis' in str(e):
raise ValueError(f'fix parentheses in einshape equation {eq!r}') from None
raise Prevention
- Lint equation strings with the depth-scanner helper before calling einshape
- Build equations from structured parts (dim lists) rather than string concatenation
- Add unit tests for every equation constant in your codebase
When it happens
Trigger: Passing an equation like '...((ab -> ...' or 'a(b' to einshape/reshape helpers — any side string containing '(' with no subsequent ')'. For example jax._src.pallas.einshape.get_einshape_transforms('a(b -> abc', shape).
Common situations: Hand-writing einshape equations with a typo (missing ')'); dynamically building equation strings that drop a closing paren; porting numpy reshape logic to einshape notation incorrectly.
Related errors
- Equation must contain exactly one '->'
- Inconsistent size for {name}: {dim_sizes[name]} vs {shape_va
- Size mismatch for group {group}: expected {shape_val}, got {
- numpy masked arrays are not supported as direct inputs to JA
- Python int {value} too large to convert to int64
AI-assisted analysis of jax-ml/jax@1e1c6a8fc0 (2026-08-27).
Data as JSON: /api/errors/9589620867adbe33.
Report an issue: GitHub.