{"record":{"id":"c69b72a7641fc038","repo":"jax-ml/jax","slug":"jax-numpy-block-does-not-allow-tuples-got","errorCode":null,"errorMessage":"jax.numpy.block does not allow tuples, got {}","messagePattern":"jax\\.numpy\\.block does not allow tuples, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"jax/_src/numpy/lax_numpy.py","lineNumber":4992,"sourceCode":"      raise ValueError(\"invalid entry in choice array\")\n  elif mode == 'wrap':\n    arr = asarray(a) % N\n  elif mode == 'clip':\n    arr = clip(a, 0, N - 1)\n  else:\n    raise ValueError(f\"mode={mode!r} not understood. Must be 'raise', 'wrap', or 'clip'\")\n\n  arr, *choices = broadcast_arrays(arr, *choices)\n  return array(choices)[(arr,) + indices(arr.shape, sparse=True)]\n\n\ndef _atleast_nd(x: ArrayLike, n: int) -> Array:\n  m = np.ndim(x)\n  return lax.broadcast(x, (1,) * (n - m)) if m < n else asarray(x)\n\ndef _block(xs: ArrayLike | list[Any]) -> tuple[Array, int]:\n  if isinstance(xs, tuple):\n    raise ValueError(\"jax.numpy.block does not allow tuples, got {}\"\n                     .format(xs))\n  elif isinstance(xs, list):\n    if len(xs) == 0:\n      raise ValueError(\"jax.numpy.block does not allow empty list arguments\")\n    xs_tup, depths = unzip2([_block(x) for x in xs])\n    if any(d != depths[0] for d in depths[1:]):\n      raise ValueError(\"Mismatched list depths in jax.numpy.block\")\n    rank = max(depths[0], max(np.ndim(x) for x in xs_tup))\n    xs_tup = tuple(_atleast_nd(x, rank) for x in xs_tup)\n    return concatenate(xs_tup, axis=-depths[0]), depths[0] + 1\n  else:\n    return asarray(xs), 1\n\n\n@export\n@api.jit\ndef block(arrays: ArrayLike | list[Any]) -> Array:\n  \"\"\"Create an array from a list of blocks.","sourceCodeStart":4974,"sourceCodeEnd":5010,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/numpy/lax_numpy.py#L4974-L5010","documentation":"jax.numpy.block accepts only lists (not tuples) as the nested layout specification, unlike NumPy which accepts either. The internal _block helper explicitly rejects tuple inputs with this ValueError. This is a deliberate JAX API restriction for consistency.","triggerScenarios":"Calling jnp.block(((a, b), (c, d))) with parentheses instead of brackets — i.e. tuples of tuples — anywhere in the nesting, including a single level like jnp.block((a, b)).","commonSituations":"Code ported from np.block that used tuples; or automatic conversion of lists to tuples by libraries like dataclasses, namedtuples, or pytrees that then feed the result into jnp.block.","solutions":["Replace all parentheses with square brackets: jnp.block([[a, b], [c, d]])","If the structure comes from a tuple-producing pipeline, convert it: jnp.block(list(map(list, nested_tuple)))"],"exampleFix":"// before\nout = jnp.block(((a, b), (c, d)))\n// after\nout = jnp.block([[a, b], [c, d]])","handlingStrategy":"validation","validationCode":"xs = list(map(list, xs)) if isinstance(xs, tuple) else xs\nout = jnp.block(xs)","typeGuard":"def is_block_list(xs) -> bool:\n    return isinstance(xs, list)","tryCatchPattern":null,"preventionTips":["Always use square brackets for jnp.block layouts","Convert pytree tuples to lists before feeding block"],"tags":["jax","block","tuple-vs-list","valueerror"],"backgroundTag":"wrong-container-type-argument","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}