jax-ml/jax · error · ValueError

{x.shape=} does not match expected shape {expected_shape}

Error message

{x.shape=} does not match expected shape {expected_shape}

What it means

Scatter's abstract eval computes the expected shape of the value from the ref shape and the indices (via _indexed_shape) and the provided value array x does not match. The value must exactly fill the region selected by the indices.

Source

Thrown at jax/_src/pallas/mosaic/sc_primitives.py:328

  flat_args, tree = jax.tree.flatten((ref, transforms, indices, mask))
  return gather_p.bind(*flat_args, tree=tree)


scatter_p = jax_core.Primitive("scatter")
scatter_p.is_effectful = lambda params: True
scatter_p.multiple_results = True


@scatter_p.def_effectful_abstract_eval
def _scatter_abstract_eval(*flat_args, tree, add):
  ref, transforms, indices, x, mask = jax.tree.unflatten(tree, flat_args)
  if transforms:
    ref = state_types.TransformedRef(ref, transforms)
  if ref.dtype not in (jnp.int32, jnp.float32):
    raise TypeError(f"ref.dtype={ref.dtype} must be int32 or float32")
  expected_shape = _indexed_shape(ref, indices)
  if x.shape != expected_shape:
    raise ValueError(
        f"{x.shape=} does not match expected shape {expected_shape}"
    )
  if x.dtype != ref.dtype:
    raise TypeError(f"val.dtype={x.dtype} != ref.dtype={ref.dtype}")
  if mask is not None:
    if mask.shape != expected_shape:
      raise ValueError(
          f"{mask.shape=} does not match expected shape {expected_shape}"
      )
    if mask.dtype != jnp.bool:
      raise TypeError(f"Mask must be a boolean array, got {mask.dtype}")
  effects: set[jax_core.Effect] = {state_types.WriteEffect(0)}
  if add:
    effects.add(state_types.ReadEffect(0))
  return (), effects


@sc_lowering.register_lowering_rule(scatter_p)

View on GitHub (pinned to 1e1c6a8fc0)

Solutions

  1. Print/inspect _indexed_shape(ref, indices) (shape arithmetic: ref shape minus indexed dims) and reshape x to match
  2. Fix the index shapes so the selected region matches x.shape
  3. Explicitly broadcast/reshape x before calling store_scatter/addupdate_scatter

Example fix

// before
sc_primitives.store_scatter(ref, idx, x)  # x.shape=(8, 32), expected=(8, 16)

// after
sc_primitives.store_scatter(ref, idx, x.reshape(8, 16))  # or fix idx/block shapes
Defensive patterns

Strategy: validation

Validate before calling

expected = _indexed_shape(ref, indices)  # or reimplement: ref.shape minus indexed dims
assert x.shape == expected, (x.shape, expected)

Type guard

def scatter_shapes_ok(ref, indices, x) -> bool:
    indexed = sum(i.shape[-1] if hasattr(i, 'shape') else 1 for i in indices)
    return tuple(x.shape) == tuple(ref.shape[indexed:])

Prevention

When it happens

Trigger: Passing an x whose shape differs from _indexed_shape(ref, indices), e.g. indices of shape (N,) selecting rows of size M but x shaped (N, K) with K != M, or a mismatched leading dimension.

Common situations: Off-by-one in block sizes; broadcasting assumptions from NumPy that Pallas does not make; changing indices semantics (per-element vs per-slice) when porting code.

Related errors


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