jax-ml/jax · error · TypeError

stop_gradient only works on valid JAX arrays, but input argu

Error message

stop_gradient only works on valid JAX arrays, but input argument is: {x}

What it means

FromPickle found a node tuple whose size is not the expected 6 elements. A pickled PyTreeDef stream is corrupt or was produced by an incompatible serialization format/version.

Source

Thrown at jax/_src/ad_util.py:99

    return f'Zero({self.aval})'
  def instantiate(self):
    return zeros_like_aval(self.aval)

register_pytree_node(Zero, lambda z: ((), z.aval), lambda aval, _: Zero(aval))

def p2tz(primal_value):
  return Zero(typeof(primal_value).to_tangent_aval())

def p2cz(primal_value):
  return Zero(typeof(primal_value).to_ct_aval())

def a2tz(primal_aval):
  return Zero(primal_aval.to_tangent_aval())


def _stop_gradient_impl[T](x: T) -> T:
  if not core.valid_jaxtype(x):
    raise TypeError("stop_gradient only works on valid JAX arrays, but "
                    f"input argument is: {x}")
  return x

stop_gradient_p : Primitive = Primitive('stop_gradient')
stop_gradient_p.def_impl(_stop_gradient_impl)
stop_gradient_p.def_abstract_eval(lambda x: x)


# User-facing version of `Zero`
class SymbolicZero:
  def __init__(self, aval: core.AbstractValue) -> None:
    self.aval = aval

  def __repr__(self) -> str:
    return self.__class__.__name__

  # TODO(mattjj,frostig): this forwards attr lookup to self.aval delegate;
  # should dedup with core.Tracer.__getattr__ which does the same thing

View on GitHub (pinned to 1e1c6a8fc0)

Solutions

  1. Re-save the pickle with the currently running jaxlib version
  2. Verify the pickle payload integrity (checksum/size) before loading
  3. Avoid hand-editing pickled treedefs; recompute structures from data

Example fix

# before
treedef = pickle.loads(old_checkpoint['treedef'])  # from older jaxlib
# after
# regenerate: _, treedef = jax.tree_util.tree_flatten(fresh_params)
Defensive patterns

Strategy: fallback

Validate before calling

import jax
# check pickle payload shape before unpickling where possible
# simplest: wrap unpickle and fall back to regeneration

Try / catch

try:
    treedef = pickle.loads(data)
except Exception as e:
    if 'Malformed pickled PyTreeDef' in str(e):
        _, treedef = jax.tree_util.tree_flatten(fresh_reference_obj)
    else:
        raise

Prevention

When it happens

Trigger: Unpickling a PyTreeDef whose __getstate__ payload contains tuples of length != 6, e.g. hand-crafted pickles or pickles from a different jaxlib version with a different node format.

Common situations: Loading checkpoints/saved states across jaxlib versions; truncated or manually edited pickle data; pickle protocol incompatibilities.

Related errors


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