jax-ml/jax · error · TypeError

Encountered unexpected shape dimension {d}

Error message

Encountered unexpected shape dimension {d}

What it means

During export, JAX substitutes fake constant dims for symbolic ones when preparing operands for underlying lowering. If a non-constant dimension is not a _DimExpr (e.g. a numpy object, a string, or a dim from a foreign tracer), it cannot be faked and raises TypeError.

Source

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

  opt_einsum.contract_path to parse the specification.
  """

  # Replace the polymorphic shapes with some concrete shapes for calling
  # into opt_einsum.contract_path, because the latter wants to compute the
  # sizes of operands and intermediate results.
  fake_ops = []
  for operand in operands:
    # We replace only array operands
    if not hasattr(operand, "dtype"):
      fake_ops.append(operand)
    else:
      shape = np.shape(operand)
      def fake_dim(d):
        if core.is_constant_dim(d):
          return d
        else:
          if not isinstance(d, _DimExpr):
            raise TypeError(f"Encountered unexpected shape dimension {d}")
          # It is Ok to replace all polynomials with the same value. We may miss
          # here some errors due to non-equal dimensions, but we catch them
          # later.
          return 8
      fake_ops.append(api.ShapeDtypeStruct(tuple(map(fake_dim, shape)),
                                           operand.dtype))

  contract_fake_ops, contractions = opt_einsum.contract_path(*fake_ops,
                                                             **kwargs)
  contract_operands = []
  for operand in contract_fake_ops:
    idx = tuple(i for i, fake_op in enumerate(fake_ops) if operand is fake_op)
    assert len(idx) == 1
    contract_operands.append(operands[idx[0]])
  return contract_operands, contractions

# To implement shape-constraint checking we use a shape assertion primitive.
#    shape_assertion_p.bind(assert_what: bool, *error_message_inputs,

View on GitHub (pinned to 1e1c6a8fc0)

Solutions

  1. Ensure all non-constant dims in operand shapes are genuine symbolic dims created by the current export's shape polymorphism
  2. Materialize shapes to plain ints / re-create inputs as jnp arrays before export
  3. Align jax/jaxlib versions so dim objects are the internal _DimExpr type

Example fix

# before
x = some_external_array  # shape contains object dims
exp = jax.export.export(shapes('n,'))(f)
# after
x = jnp.asarray(x)  # normalize to a JAX array with int/symbolic dims
exp = jax.export.export(shapes('n,'))(f)
Defensive patterns

Strategy: validation

Validate before calling

def clean_shape(a):
    return all(isinstance(d, int) or is_symbolic_dim(d) for d in np.shape(a))
assert clean_shape(x), 'operand has non-int/non-symbolic dims'

Type guard

def exportable_operand(a) -> bool:
    return isinstance(a, jax.Array) or all(isinstance(d, (int,)) or hasattr(d, '_factors') for d in np.shape(a))

Try / catch

try:
    exp = jax.export.export(shapes)(fn)
except TypeError as e:
    if 'unexpected shape dimension' in str(e): inputs = [jnp.asarray(i) for i in inputs]; retry()

Prevention

When it happens

Trigger: An operand's shape contains a non-int, non-_DimExpr dimension object — e.g. a Tracer from another transformation, np.str_, or a custom dim class — while exporting with polymorphic shapes.

Common situations: Composing jax.export with other transforms producing exotic dim objects; passing arrays whose shapes were built by external libs inserting object dims; JAX version incompatibilities in the dim representation.

Related errors


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