{"record":{"id":"fb3005ac12871f28","repo":"jax-ml/jax","slug":"multi-dot-requires-at-least-two-arrays-got-len-ar","errorCode":null,"errorMessage":"multi_dot requires at least two arrays; got len(arrays)={len(arrs)}","messagePattern":"multi_dot requires at least two arrays; got len\\(arrays\\)=(.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"jax/_src/numpy/linalg.py","lineNumber":2231,"sourceCode":"\n  >>> result3 = jnp.linalg.multi_dot([x, y, z])\n  >>> jnp.allclose(result1, result3, atol=1E-4)\n  Array(True, dtype=bool)\n\n  We can use JAX's :ref:`ahead-of-time-lowering` tools to estimate the total flops\n  of each approach, and confirm that ``multi_dot`` is choosing the more efficient\n  option:\n\n  >>> jax.jit(lambda x, y, z: (x @ y) @ z).lower(x, y, z).cost_analysis()['flops']\n  600000.0\n  >>> jax.jit(lambda x, y, z: x @ (y @ z)).lower(x, y, z).cost_analysis()['flops']\n  30000.0\n  >>> jax.jit(jnp.linalg.multi_dot).lower([x, y, z]).cost_analysis()['flops']\n  30000.0\n  \"\"\"\n  arrs = list(ensure_arraylike('jnp.linalg.multi_dot', *arrays))\n  if len(arrs) < 2:\n    raise ValueError(f\"multi_dot requires at least two arrays; got len(arrays)={len(arrs)}\")\n  if not (arrs[0].ndim in (1, 2) and arrs[-1].ndim in (1, 2) and\n          all(a.ndim == 2 for a in arrs[1:-1])):\n    raise ValueError(\"multi_dot: input arrays must all be two-dimensional, except for\"\n                     \" the first and last array which may be 1 or 2 dimensional.\"\n                     f\" Got array shapes {[a.shape for a in arrs]}\")\n  if any(a.shape[-1] != b.shape[0] for a, b in zip(arrs[:-1], arrs[1:])):\n    raise ValueError(\"multi_dot: last dimension of each array must match first dimension\"\n                     f\" of following array. Got array shapes {[a.shape for a in arrs]}\")\n  einsum_axes: list[tuple[int, ...]] = [(i, i+1) for i in range(len(arrs))]\n  if arrs[0].ndim == 1:\n    einsum_axes[0] = einsum_axes[0][1:]\n  if arrs[-1].ndim == 1:\n    einsum_axes[-1] = einsum_axes[-1][:1]\n  return einsum.einsum(*itertools.chain(*zip(arrs, einsum_axes)),  # pyrefly: ignore[no-matching-overload]\n                       optimize='auto', precision=precision)\n\n\n@export","sourceCodeStart":2213,"sourceCodeEnd":2249,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/numpy/linalg.py#L2213-L2249","documentation":"jnp.linalg.multi_dot(arrays) chains matrix products with an optimized parenthesization (like np.linalg.multi_dot / scipy.linalg.blas.dgemm_seq). Chaining requires at least two arrays; passing a single array or an empty list fails this check.","triggerScenarios":"jnp.linalg.multi_dot([a]) or jnp.linalg.multi_dot([]); also multi_dot(*mats) where mats happens to contain one element, or unrolling a loop that collapses to a single array.","commonSituations":"Dynamic product chains built from lists whose length varies and can degenerate to 0 or 1; refactoring chained @ expressions into multi_dot without preserving at least two operands.","solutions":["Handle the degenerate cases yourself: return the single array (or identity) when len < 2.","Guard the call: if len(arrays) < 2 use plain matmul or return the element.","Fix the list construction so it always has >= 2 arrays."],"exampleFix":"// before\nout = jnp.linalg.multi_dot(mats)  # mats may be [a]\n// after\nout = mats[0] if len(mats) == 1 else jnp.linalg.multi_dot(mats)","handlingStrategy":"type-guard","validationCode":"if len(arrays) < 2:\n    out = arrays[0] if arrays else None\nelse:\n    out = jnp.linalg.multi_dot(arrays)","typeGuard":"def multi_dot_ok(arrays) -> bool:\n    return len(arrays) >= 2","tryCatchPattern":null,"preventionTips":["Guard degenerate chains (0 or 1 arrays) yourself","Log list length when building chains dynamically"],"tags":["jax","numpy","linalg","matmul","argument-validation"],"backgroundTag":"invalid-argument-count","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}