{"record":{"id":"4ce16539dc49d381","repo":"huggingface/transformers","slug":"cannot-flatten-type-obj-name-for-pytree-con","errorCode":null,"errorMessage":"Cannot flatten {type(obj).__name__} for pytree context","messagePattern":"Cannot flatten (.+?) for pytree context","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/transformers/exporters/exporter_dynamo.py","lineNumber":518,"sourceCode":"            \"v\": {k: _flatten_to_context(v, tensors) for k, v in obj.items()},\n        }\n    if isinstance(obj, (tuple, list, set, frozenset)):  # sequences/sets incl. NamedTuple\n        return {\n            \"_t\": \"seq\",\n            \"p\": _class_to_path(cls),\n            \"v\": [_flatten_to_context(i, tensors) for i in obj],\n        }\n    if isinstance(obj, types.MethodType):\n        # A bound method can't be flattened into pytree context. Models shouldn't bind methods onto\n        # objects they return at forward time (e.g. recurrent_gemma binds `get_seq_length`/\n        # `get_mask_sizes` onto its `DynamicCache`) — that pattern isn't exportable; such a model is\n        # skipped until the binding is refactored away (e.g. into a `Cache` subclass).\n        raise TypeError(\"Cannot flatten a bound method for pytree context\")\n    if hasattr(obj, \"__dict__\"):\n        state = {k: _flatten_to_context(v, tensors) for k, v in vars(obj).items()}\n        return {\"_t\": \"obj\", \"p\": _class_to_path(cls), \"s\": state}\n\n    raise TypeError(f\"Cannot flatten {type(obj).__name__} for pytree context\")\n\n\ndef _unflatten_from_context(ctx: Any, tensors: list) -> Any:\n    \"\"\"Reconstruct an object from its JSON-native context, substituting tensor index markers.\"\"\"\n    # --- Pure Python / JSON-native ---\n    if ctx is None or type(ctx) in (bool, int, float, str):\n        return ctx\n    if type(ctx) is list:\n        return [_unflatten_from_context(i, tensors) for i in ctx]\n    if type(ctx) is dict and \"_t\" not in ctx:\n        return {k: _unflatten_from_context(v, tensors) for k, v in ctx.items()}\n\n    # --- Torch objects ---\n    t = ctx[\"_t\"]\n    if t == \"tensor\":\n        return tensors[ctx[\"i\"]]\n    if t == \"layout\":\n        return getattr(torch, ctx[\"n\"])","sourceCodeStart":500,"sourceCodeEnd":536,"githubUrl":"https://github.com/huggingface/transformers/blob/a597f974857b3d92939971296bc0deb93d33d780/src/transformers/exporters/exporter_dynamo.py#L500-L536","documentation":"The catch-all branch of _flatten_to_context: an object in the traced program's pytree context is not one of the supported types (None/bool/int/float/str, enum, tuple/list/set/frozenset, dict-like, or any object with __dict__). Types without __dict__ — e.g. classes using __slots__, C-extension types, complex tensors or numpy scalars — cannot be serialized into the export context and raise this TypeError naming the type.","triggerScenarios":"A model config/attribute reachable from the traced graph holds a slotted class, a numpy scalar, a complex number, or an extension object; the flattener walks it while building the JSON-native context for the ExportedProgram.","commonSituations":"Custom model code storing non-standard objects (slots-based dataclasses, numpy types, third-party C objects) in state that dynamo must capture; upgrading numpy/torch so a previously-tolerated type now takes the unsupported path.","solutions":["Convert the offending value to a supported type before export (int/float/str, tuple/list/dict, or a plain class with __dict__).","If it is your class using __slots__, drop __slots__ or add a __dict__-carrying base so state can be captured.","Keep numpy scalars out of module/config state — cast to Python builtins at model init.","Locate the value first: the error names the type; grep your model for that type in attributes reachable from forward."],"exampleFix":"# before (model code)\nclass WindowSpec:\n    __slots__ = (\"size\", \"stride\")  # no __dict__ -> unflattenable\n\n# after\nclass WindowSpec:  # plain class with __dict__\n    def __init__(self, size, stride):\n        self.size, self.stride = size, stride","handlingStrategy":"type-guard","validationCode":"import types\n\nSUPPORTED_PRIMITIVES = (type(None), bool, int, float, str)\n\ndef flattenable(obj) -> bool:\n    if obj is None or isinstance(obj, SUPPORTED_PRIMITIVES):\n        return True\n    if isinstance(obj, (tuple, list, set, frozenset)):\n        return all(flattenable(i) for i in obj)\n    if isinstance(obj, types.MappingProxyType | dict):\n        return all(flattenable(v) for v in obj.values())\n    if hasattr(obj, \"__dict__\"):\n        return all(flattenable(v) for v in vars(obj).values())\n    return False\n\nassert flattenable(model_state_reachable_from_forward), \"non-serializable object would break export\"","typeGuard":"def is_pytree_context_safe(obj) -> bool:\n    return flattenable(obj)","tryCatchPattern":"try:\n    DynamoExporter().export(model, inputs, cfg)\nexcept TypeError as e:\n    if \"Cannot flatten\" in str(e):\n        # str(e) names the type — find and convert it in model state, then retry once\n        bad = str(e).split(\"Cannot flatten\")[1].split(\" for pytree\")[0].strip()\n        raise RuntimeError(f\"convert {bad} instances in model state to plain builtins/dataclasses\") from e\n    raise","preventionTips":["Keep model/config state to builtins and plain classes (no __slots__, no numpy scalars, no C objects)","Cast numpy values to int/float/str at model init","Smoke-test custom models with a tiny Dynamo export before adding them to the export matrix"],"tags":["export","dynamo","pytree","serialization"],"backgroundTag":null,"analyzedSha":"a597f974857b3d92939971296bc0deb93d33d780","analyzedAt":"2026-08-14T18:24:08.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}