{"record":{"id":"46bd8cb5fe97029c","repo":"huggingface/transformers","slug":"expected-len-combined-cache-data-to-be-4-or","errorCode":null,"errorMessage":"Expected {len(combined_cache_data) = } to be 4 or 6.\n{combined_cache_data = }","messagePattern":"Expected (.+?) to be 4 or 6\\.\n(.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/transformers/cache_utils.py","lineNumber":1986,"sourceCode":"    >>> outputs.past_key_values # access cache filled with key/values from generation\n    EncoderDecoderCache()\n    ```\n    \"\"\"\n\n    def __init__(self, *caches) -> None:\n        # For dp and ddp support, if only one argument is passed, it should be an iterable of DynamicCache ddp data\n        if len(caches) == 1:\n            self_attention_cache_data, cross_attention_cache_data = [], []\n            for combined_cache_data in caches[0]:\n                if len(combined_cache_data) == 6:  # two tuple of style (self_attn_k, self_attn_v, self_attn_sliding)\n                    self_attention_cache_data.append(combined_cache_data[:3])\n                    cross_attention_cache_data.append(combined_cache_data[3:])\n                # To support old DDP-style init, we handle the case where the tuple has no sliding window tensor\n                elif len(combined_cache_data) == 4:  # two tuple of style (self_attn_k, self_attn_v)\n                    self_attention_cache_data.append(combined_cache_data[:2])\n                    cross_attention_cache_data.append(combined_cache_data[2:])\n                else:\n                    raise ValueError(f\"Expected {len(combined_cache_data) = } to be 4 or 6.\\n{combined_cache_data = }\")\n            self.self_attention_cache = DynamicCache(self_attention_cache_data)\n            self.cross_attention_cache = DynamicCache(cross_attention_cache_data)\n        # Otherwise, we should get two arguments, a self-attention cache and a cross-attention cache\n        elif len(caches) == 2:\n            if not isinstance(caches[0], Cache) or not isinstance(caches[1], Cache):\n                raise TypeError(f\"One of the two arguments is not a Cache: {type(caches[0]) = }, {type(caches[1]) = }\")\n            self.self_attention_cache = caches[0]\n            self.cross_attention_cache = caches[1]\n        # Error case\n        else:\n            raise ValueError(f\"Expected 1 or 2 arguments, got {len(caches)}\")\n\n        self.is_updated = {}\n        for layer_idx in range(len(self.cross_attention_cache)):\n            self.is_updated[layer_idx] = bool(self.cross_attention_cache.get_seq_length(layer_idx) > 0)\n\n    def __iter__(self):\n        \"\"\"Returns tuples of style (self_attn_k, self_attn_v, self_attn_sliding, cross_attn_k, cross_attn_v, cross_attn_sliding)\"\"\"","sourceCodeStart":1968,"sourceCodeEnd":2004,"githubUrl":"https://github.com/huggingface/transformers/blob/a597f974857b3d92939971296bc0deb93d33d780/src/transformers/cache_utils.py#L1968-L2004","documentation":"EncoderDecoderCache.__init__ raises ValueError in its single-argument (DDP-style) path when an element of the iterable has length other than 4 or 6. Each per-layer tuple must carry either 6 tensors (self-attn k/v/sliding + cross-attn k/v/sliding) or 4 tensors (legacy: self-attn k/v + cross-attn k/v) so it can be split into self- and cross-attention DynamicCaches.","triggerScenarios":"Passing a single iterable of per-layer cache tuples to EncoderDecoderCache where some tuple has e.g. 2, 3, or 5 elements — common when materializing caches from distributed (dp/ddp) gathered state or from legacy cache dumps with an unexpected layout.","commonSituations":"Migrating old DDP-era checkpoints/caches that stored only key/value per layer without sliding-window tensors and also dropped the cross-attn half; hand-building the iterable and mis-slicing; version upgrades that added the sliding tensor (6-tuple) where older code assumed 4.","solutions":["Ensure each per-layer entry is exactly (k_self, v_self, sliding_self, k_cross, v_cross, sliding_cross) or legacy (k_self, v_self, k_cross, v_cross)","If your data only has self-attention halves, pad the cross-attention half with None or empty tensors so each tuple is length 4/6","Prefer the two-argument form EncoderDecoderCache(self_attention_cache, cross_attention_cache) with real Cache objects instead of raw tuples"],"exampleFix":"# before\ncache = EncoderDecoderCache([(k, v) for k, v in saved_layers])  # 2-tuples -> ValueError\n\n# after\ncache = EncoderDecoderCache(\n    DynamicCache([DynamicCacheLayer.from_tensors(k, v) for k, v, _, _, _, _ in saved]),\n    DynamicCache([DynamicCacheLayer.from_tensors(k, v) for _, _, _, k, v, _ in saved]),\n)","handlingStrategy":"validation","validationCode":"for entry in caches_iterable:\n    if not isinstance(entry, tuple) or len(entry) not in (4, 6):\n        raise ValueError(f\"bad per-layer cache entry: {entry!r}\")\ncache = EncoderDecoderCache(caches_iterable)","typeGuard":"def is_valid_ddp_cache_entry(entry) -> bool:\n    return isinstance(entry, (tuple, list)) and len(entry) in (4, 6) and all(hasattr(t, \"shape\") for t in entry)","tryCatchPattern":"try:\n    cache = EncoderDecoderCache(caches_iterable)\nexcept ValueError as e:\n    if \"to be 4 or 6\" in str(e):\n        # normalize entries to 4-tuples before retry\n        fixed = [tuple(e[:2]) + tuple(e[2:4]) for e in caches_iterable if len(e) >= 4]\n        cache = EncoderDecoderCache(fixed)\n    else:\n        raise","preventionTips":["Prefer the two-Cache form: EncoderDecoderCache(self_cache, cross_cache)","When materializing from gathered DDP state, verify each per-layer tuple has (k, v[, sliding]) x2 before constructing","The sliding-window tensor is newer than the 4-tuple layout — version-skewed producers cause this"],"tags":["cache","encoder-decoder","ddp","data-layout","valueerror"],"backgroundTag":null,"analyzedSha":"a597f974857b3d92939971296bc0deb93d33d780","analyzedAt":"2026-08-14T18:24:08.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}