{"record":{"id":"7c56bbd2637776f6","repo":"jax-ml/jax","slug":"scan-got-no-values-to-scan-over-and-length-not-p","errorCode":null,"errorMessage":"scan got no values to scan over and `length` not provided.","messagePattern":"scan got no values to scan over and `length` not provided\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"jax/_src/lax/control_flow/loops.py","lineNumber":525,"sourceCode":"    except core.ConcretizationTypeError:\n      msg = ('The `length` argument to `scan` expects a concrete `int` value.'\n             ' For scan-like iteration with a dynamic length, use `while_loop`'\n             ' or `fori_loop`.')\n      raise core.ConcretizationTypeError(length, msg) from None\n    else:\n      if not all(length == l for l in lengths):\n        msg = (\"scan got `length` argument of {} which disagrees with \"\n              \"leading axis sizes {}.\")\n        raise ValueError(msg.format(length, [x.shape[0] for x in xs_flat]))\n      return length\n  else:\n    unique_lengths = set(lengths)\n    if len(unique_lengths) > 1:\n      msg = \"scan got values with different leading axis sizes: {}.\"\n      raise ValueError(msg.format(', '.join(str(x.shape[0]) for x in xs_flat)))\n    elif len(unique_lengths) == 0:\n      msg = \"scan got no values to scan over and `length` not provided.\"\n      raise ValueError(msg)\n    else:\n      return list(unique_lengths)[0]\n\ndef _capitalize(s):\n  # s.capitalize() converts s[1:] to lowercase which we don't want.\n  return s[0].capitalize() + s[1:]\n\ndef _check_carry_type(name, body_fun, in_carry, out_carry):\n  try:\n    sig = inspect.signature(body_fun)\n  except (ValueError, TypeError):\n    sig = None\n  carry_name = sig and list(sig.parameters)[0]\n  if carry_name:\n    component = lambda p: (f'the input carry component {carry_name}{keystr(p)}'\n                           if p else f'the input carry {carry_name}')\n  else:\n    component = lambda p: (f'the input carry at path {keystr(p)}'","sourceCodeStart":507,"sourceCodeEnd":543,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/lax/control_flow/loops.py#L507-L543","documentation":"scan was called with no xs values at all (empty pytree or None) and no explicit length, so there is nothing from which to infer the number of iterations and it raises ValueError.","triggerScenarios":"lax.scan(f, init) or lax.scan(f, init, None) without length; xs being an empty tuple/list.","commonSituations":"Running a fixed-iteration loop with no per-step data but forgetting length; refactoring a loop's data away without adding length=n.","solutions":["Pass an explicit length: lax.scan(f, init, xs=None, length=n_steps)","Use lax.fori_loop(0, n, body, init) for data-free loops","Provide dummy xs of shape (n,) if downstream code expects ys"],"exampleFix":"// before\ncarry, ys = lax.scan(lambda c, _: (c + 1, c), 0)\n// after\ncarry, ys = lax.scan(lambda c, _: (c + 1, c), 0, length=n_steps)","handlingStrategy":"validation","validationCode":"flat = jax.tree_util.tree_leaves(xs)\nif not flat:\n    assert length is not None, 'must pass length when xs is empty/None'","typeGuard":"def scan_args_valid(xs, length) -> bool:\n    return bool(jax.tree_util.tree_leaves(xs)) or length is not None","tryCatchPattern":"null","preventionTips":["Always pass length for data-free loops","Prefer lax.fori_loop when there is no xs","Make iteration count an explicit parameter of loop utilities"],"tags":["jax","scan","missing-length","argument-validation"],"backgroundTag":"missing-required-argument","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}