{"record":{"id":"bd58762eb0c745c9","repo":"huggingface/transformers","slug":"crop-was-called-but-the-current-layer-does-not-bd5876","errorCode":null,"errorMessage":"`crop` was called, but the current layer does not track past states. Call `activate_past_recording` before `crop` to be able to rollback the cache.","messagePattern":"`crop` was called, but the current layer does not track past states\\. Call `activate_past_recording` before `crop` to be able to rollback the cache\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"src/transformers/cache_utils.py","lineNumber":973,"sourceCode":"            if self.is_recurrent_states_initialized[i]:\n                self.recurrent_states[i] = self.recurrent_states[i].index_select(0, beam_idx.to(self.device))\n\n    def activate_past_recording(self):\n        \"\"\"\n        Calling this function will activate past state recording, meaning that a call to `update_conv_states` will\n        wait for a call to `crop` before restricting the size of the `conv_states` to `conv_kernel_size`, to be able\n        to retrieve previous full states.\n        \"\"\"\n        self.record_past = True\n\n    def crop(self, tokens_to_remove: int):\n        \"\"\"\n        Remove `tokens_to_remove` tokens from the current cache layer. This will also restrict the size of the cached states back to their\n        minimal working size, i.e. `conv_kernel_size`. This means that `crop(0)` will not necessarily always be a no-op, as it may\n        still remove useless states (i.e. states that are not needed for the next `forward`).\n        \"\"\"\n        if not self.record_past:\n            raise RuntimeError(\n                \"`crop` was called, but the current layer does not track past states. Call `activate_past_recording` before \"\n                \"`crop` to be able to rollback the cache.\"\n            )\n        if tokens_to_remove > 0:\n            raise RuntimeError(\n                \"Linear attention layers can only be cropped by passing a negative int, to specify how many tokens to remove\"\n            )\n        for i in range(self.number_of_states):\n            tokens_to_remove = abs(tokens_to_remove)\n            # In this case, simply restrict the size back to `conv_kernel_size` without cropping\n            if tokens_to_remove == 0:\n                self.conv_states[i] = self.conv_states[i][..., -self.conv_kernel_size[i] :]\n            # This both crop the last `tokens_to_remove`, as well as resize the conv states to `conv_kernel_size` as we never\n            # need more for the next forward\n            else:\n                self.conv_states[i] = self.conv_states[i][\n                    ..., -tokens_to_remove - self.conv_kernel_size[i] : -tokens_to_remove\n                ]","sourceCodeStart":955,"sourceCodeEnd":991,"githubUrl":"https://github.com/huggingface/transformers/blob/a597f974857b3d92939971296bc0deb93d33d780/src/transformers/cache_utils.py#L955-L991","documentation":"LinearAttentionCacheLayerMixin.crop() raises RuntimeError when crop() is called while record_past is False. Linear attention layers keep fixed-size conv/recurrent states that are trimmed to conv_kernel_size after each forward; to support rollback (beam search, assisted decoding) the layer must retain extra history, which is only enabled by calling activate_past_recording() first.","triggerScenarios":"Calling cache.crop(...) (e.g. via Cache.crop or beam-search rollback paths in generation) on a cache whose linear attention layers never had activate_past_recording() called. Generation code paths that call crop on caches (beam search, and _supports_default_streaming_layout rollback) hit this when the cache was created fresh without recording enabled.","commonSituations":"Using generate() with beam search or any strategy that rewinds the cache on a model with linear attention / conv states (e.g. Mamba-style or hybrid models) without enabling past recording; manually calling DynamicCache-style crop APIs on a linear-attention cache.","solutions":["Call cache.activate_past_recording() before the forward pass that precedes crop (it sets record_past=True on all layers that support it)","If using generate(), prefer a decoding strategy that does not need rollback (e.g. greedy/multinomial sampling) for linear-attention models","Do not call crop() on a fresh cache that has never run a forward — recording is only meaningful after states exist"],"exampleFix":"// before\nout = model(**inputs, cache=cache)\ncache.crop(-2)  # RuntimeError\n\n// after\ncache.activate_past_recording()\nout = model(**inputs, cache=cache)\ncache.crop(-2)","handlingStrategy":"validation","validationCode":"if any(\n    isinstance(l, LinearAttentionCacheLayerMixin) and not l.record_past\n    for l in cache.layers\n):\n    cache.activate_past_recording()\nout = model(**inputs, cache=cache)\ncache.crop(-2)","typeGuard":null,"tryCatchPattern":"try:\n    cache.crop(-n)\nexcept RuntimeError as e:\n    if \"activate_past_recording\" in str(e):\n        cache.activate_past_recording()  # re-record from next forward, then retry after a step\n    else:\n        raise","preventionTips":["Call cache.activate_past_recording() once before generate() when using rollback-capable strategies on linear attention models","Treat recording as an explicit opt-in: fresh caches never track past states","Note crop(0) is not a no-op on linear attention layers — it trims states to conv_kernel_size"],"tags":["cache","linear-attention","generation","rollback","runtimeerror"],"backgroundTag":null,"analyzedSha":"a597f974857b3d92939971296bc0deb93d33d780","analyzedAt":"2026-08-14T18:24:08.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}