{"record":{"id":"cb83336cd6546635","repo":"jax-ml/jax","slug":"the-names-should-be-exclusive-and-should-not-inter","errorCode":null,"errorMessage":"The names should be exclusive and should not intersect in `names_which_can_be_saved` and `names_which_can_be_offloaded`. Got names_which_can_be_saved={set(names_which_can_be_saved)}, names_which_can_be_offloaded={set(names_which_can_be_offloaded)} and the intersection={set(intersection)}","messagePattern":"The names should be exclusive and should not intersect in `names_which_can_be_saved` and `names_which_can_be_offloaded`\\. Got names_which_can_be_saved=(.+?), names_which_can_be_offloaded=(.+?) and the intersection=(.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"jax/_src/ad_checkpoint.py","lineNumber":174,"sourceCode":"  offload_dst: str\n\n  def __call__(self, prim, *_, **params) -> Any:\n    if prim is name_p and params['name'] in self.names_which_can_be_saved:\n      return pe.Saveable\n    if prim is name_p and params['name'] in self.names_which_can_be_offloaded:\n      return pe.Offloadable(src=self.offload_src, dst=self.offload_dst)\n    return pe.Recompute  # not saveable unless it's in the allow-list\n\ndef save_and_offload_only_these_names(\n    *, names_which_can_be_saved, names_which_can_be_offloaded,\n    offload_src, offload_dst):\n  \"\"\"Same as ``save_only_these_names``, but offload to CPU memory instead of\n  recomputing.\"\"\"\n  names_which_can_be_saved = frozenset(names_which_can_be_saved)\n  names_which_can_be_offloaded = frozenset(names_which_can_be_offloaded)\n  intersection = names_which_can_be_saved & names_which_can_be_offloaded\n  if intersection:\n    raise ValueError(\n        \"The names should be exclusive and should not intersect in\"\n        \" `names_which_can_be_saved` and `names_which_can_be_offloaded`. Got\"\n        f\" names_which_can_be_saved={set(names_which_can_be_saved)},\"\n        f\" names_which_can_be_offloaded={set(names_which_can_be_offloaded)} and\"\n        f\" the intersection={set(intersection)}\")\n  return SaveAndOffloadOnlyTheseNames(\n      names_which_can_be_saved, names_which_can_be_offloaded,\n      offload_src, offload_dst)\n\n\ndef save_from_both_policies(policy_1, policy_2):\n  \"\"\"Logical OR of the given policies.\n\n  A residual is saveable iff it is saveable according to either policy.\"\"\"\n  def policy(prim, *args, **params):\n    out1 = policy_1(prim, *args, **params)\n    out2 = policy_2(prim, *args, **params)\n    if not (isinstance(out1, bool) and isinstance(out2, bool)):","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/ad_checkpoint.py#L156-L192","documentation":"While flattening with keypaths, jaxlib encounters a tuple whose type (or base) looks like a namedtuple and reads _fields to emit GetAttrKey entries. If _fields is not a tuple or its length differs from the tuple instance's size, this error is thrown during full tree flattening (not just one-level).","triggerScenarios":"jax.tree.flatten_with_path / tree_map_with_path over a structure containing a pseudo-namedtuple: a tuple subclass with a bogus _fields attribute, or a namedtuple whose instance length was altered (e.g. via tuple.__new__ tricks or serialization that dropped fields).","commonSituations":"Deserializing namedtuple-like objects (pickle from an older class version with different fields), libraries faking namedtuples, duck-typed _fields properties that return lists or generators.","solutions":["Check type(node)._fields is a tuple and len(node) == len(type(node)._fields) for suspect nodes","Reconstruct objects as real namedtuples after deserialization","Avoid defining _fields on non-namedtuple tuple subclasses","Use is_leaf to short-circuit flattening of the malformed node"],"exampleFix":"# before\nrestored = pickle.loads(blob)  # namedtuple with fewer elements than _fields\njax.tree.flatten_with_path(restored)\n\n# after\nRestored = collections.namedtuple('Restored', Restored._fields[:len(restored)])\nrestored = Restored(*restored)\njax.tree.flatten_with_path(restored)","handlingStrategy":"validation","validationCode":"def validate_tree_for_keypaths(tree):\n    for x in jax.tree.leaves(tree, is_leaf=lambda v: isinstance(v, tuple) and hasattr(type(v), '_fields')):\n        pass  # leaf override keeps malformed namedtuples out of flattening\n\ndef namedtuple_intact(x) -> bool:\n    f = getattr(type(x), '_fields', None)\n    return not (isinstance(x, tuple) and f is not None) or (isinstance(f, tuple) and len(f) == len(x))","typeGuard":"def is_safe_pytree_input(tree) -> bool:\n    stack = [tree]\n    while stack:\n        v = stack.pop()\n        if isinstance(v, tuple) and hasattr(type(v), '_fields'):\n            if not isinstance(type(v)._fields, tuple) or len(type(v)._fields) != len(v):\n                return False\n        elif isinstance(v, (list, tuple)):\n            stack.extend(v)\n        elif isinstance(v, dict):\n            stack.extend(v.values())\n    return True","tryCatchPattern":null,"preventionTips":["Rebuild namedtuples after unpickling from older schemas","Don't monkey-patch _fields","Run tree_flatten_with_path over full config trees in tests"],"tags":["pytree","namedtuple","jax","pickle","tree-flatten-with-path"],"backgroundTag":"pytree-structure-mismatch","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}