jax-ml/jax · error · TypeError

prevent_cse must be a bool or tuple of bools, got {type(prev

Error message

prevent_cse must be a bool or tuple of bools, got {type(prevent_cse)=}

What it means

PyTreeDef::UnflattenImpl rebuilds a structure from a treedef and a list of leaves; when the traversal needs another leaf but the iterator is exhausted, it throws 'Too few leaves for PyTreeDef; expected %d, got %d'. num_leaves() is the treedef's expectation, leaf_count is what was supplied so far.

Source

Thrown at jax/_src/ad_checkpoint.py:380

    @partial(jax.checkpoint, static_argnums=(1,))
    def foo(x, y):
      with jax.ensure_compile_time_eval():
        y_pos = y > 0
      if y_pos:
        ...
      else:
        ...

  As an alternative to using ``static_argnums`` (and
  ``jax.ensure_compile_time_eval``), it may be easier to compute some values
  outside the :func:`jax.checkpoint`-decorated function and then close over them.
  """
  if isinstance(static_argnums, int):
    static_argnums = static_argnums,
  if isinstance(prevent_cse, Sequence):
    prevent_cse = tuple(prevent_cse)
  if not isinstance(prevent_cse, (tuple, bool)):
    raise TypeError("prevent_cse must be a bool or tuple of bools, got "
                    f"{type(prevent_cse)=}")

  if config.remat3.value:
    policy = None if policy is nothing_saveable else policy
    return remat3(fun, policy=policy, static_argnums=static_argnums,
                  static_argnames=static_argnames, prevent_cse=prevent_cse)

  @wraps(fun)
  @api_boundary
  def fun_remat(*args, **kwargs):
    debug = api_util.debug_info(
        "checkpoint / remat", fun,
        args, kwargs, static_argnums=static_argnums)
    fun_, args = _remat_static_argnums(fun, static_argnums, args)
    args_flat, in_tree = tracing_registry.flatten((args, kwargs))
    api_util.check_no_transformed_refs_args(lambda: debug, args_flat)
    in_avals = [core.shaped_abstractify(x) for x in args_flat]
    jaxpr, consts, out_tree = _trace_to_jaxpr(fun_, in_tree, tuple(in_avals), debug)

View on GitHub (pinned to 1e1c6a8fc0)

Solutions

  1. Check len(leaves) == treedef.num_leaves before unflattening
  2. Flatten and unflatten with the same is_leaf predicate so treedef and leaves agree
  3. If you intentionally dropped leaves, use treedef.replace_like / jax.tree.map(None-safe) patterns instead of filtering the leaf list
  4. Log treedef.num_leaves vs len(leaves) at the call site when debugging

Example fix

# before
leaves = [l for l in leaves if l is not None]
out = treedef.unflatten(leaves)  # ValueError: too few leaves

# after
assert len(leaves) == treedef.num_leaves, (len(leaves), treedef.num_leaves)
out = treedef.unflatten(leaves)
Defensive patterns

Strategy: validation

Validate before calling

if len(leaves) != treedef.num_leaves:
    raise ValueError(f'need {treedef.num_leaves} leaves, got {len(leaves)}')
out = treedef.unflatten(leaves)

Try / catch

try:
    out = treedef.unflatten(leaves)
except ValueError as e:
    if 'Too few leaves' in str(e):
        raise ValueError(f'leaf count mismatch: have {len(leaves)}, treedef wants {treedef.num_leaves}') from e
    raise

Prevention

When it happens

Trigger: Calling treedef.unflatten(leaves) or jax.tree.unflatten(treedef, leaves) with fewer leaves than treedef.num_leaves (e.g. passing a filtered or truncated leaf list, or leaves from a different treedef).

Common situations: Filtering leaves (e.g. dropping None or padding leaves) before unflattening; using leaves flattened under is_leaf but unflattening with the default treedef; mixing treedefs when batching/stacking params; vmap/pmap reshaping code that slices leaves.

Related errors


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