DynamicCache.crop(0) retains the full KV cache and oversized negative crops retain stale tokens
System Info
- Transformers source revision:
71554973d2c3123a23f2a1d6b7b63568b4e4df62
- OS: Windows 10 (
10.0.26200)
- Python: 3.11.9
- PyTorch: 2.13.0+cpu
Who can help?
Generation/cache maintainers.
Information
The problem occurs in a minimal standalone script and does not depend on a model, dataset, GPU, or network access.
Reproduction
import torch
from transformers import DynamicCache
key = torch.arange(3, dtype=torch.float32).reshape(1, 1, 3, 1)
cache = DynamicCache()
cache.update(key, key.clone(), layer_idx=0)
cache.crop(0)
print(cache.get_seq_length()) # 3, expected 0
cache = DynamicCache()
cache.update(key, key.clone(), layer_idx=0)
cache.crop(-5)
print(cache.get_seq_length()) # 1, expected 0
DynamicLayer.crop handles every max_length <= 0 as a relative crop:
if max_length <= 0:
max_length = self.get_seq_length() - abs(max_length)
For crop(0), this computes the current sequence length and triggers the early return, so nothing is removed. For a three-token cache, crop(-5) computes -2; Python slicing with [..., :-2, :] then retains one stale token instead of producing an empty cache.
Expected behavior
crop(0) should empty initialized key and value tensors along the sequence dimension.
- A negative value should remove that many trailing tokens.
- Removing at least the current sequence length should either empty the cache or raise a clear validation error. It should never silently retain tokens.
This is important for rollback and cache-reuse flows, including speculative or custom generation. A complete rollback can silently preserve old key/value states, causing later decoding to attend to stale tokens or creating cache-position and attention-mask length mismatches.
Suggested implementation direction
- Treat only
max_length < 0 as relative removal, keeping zero as an absolute target.
- Clamp the computed target to zero, or explicitly reject oversized negative removal.
- Audit sliding-window, hybrid, and composite cache layers so tensors and length metadata remain consistent.
- Add parameterized regression coverage for
2, 0, -1, -3, and -5, plus a full rollback followed by an append.
I searched existing open and closed issues for crop(0), DynamicCache.crop, negative cache crops, and stale cache tokens, and did not find a report for this behavior.
DynamicCache.crop(0)retains the full KV cache and oversized negative crops retain stale tokensSystem Info
71554973d2c3123a23f2a1d6b7b63568b4e4df6210.0.26200)Who can help?
Generation/cache maintainers.
Information
The problem occurs in a minimal standalone script and does not depend on a model, dataset, GPU, or network access.
Reproduction
DynamicLayer.crophandles everymax_length <= 0as a relative crop:For
crop(0), this computes the current sequence length and triggers the early return, so nothing is removed. For a three-token cache,crop(-5)computes-2; Python slicing with[..., :-2, :]then retains one stale token instead of producing an empty cache.Expected behavior
crop(0)should empty initialized key and value tensors along the sequence dimension.This is important for rollback and cache-reuse flows, including speculative or custom generation. A complete rollback can silently preserve old key/value states, causing later decoding to attend to stale tokens or creating cache-position and attention-mask length mismatches.
Suggested implementation direction
max_length < 0as relative removal, keeping zero as an absolute target.2,0,-1,-3, and-5, plus a full rollback followed by an append.I searched existing open and closed issues for
crop(0),DynamicCache.crop, negative cache crops, and stale cache tokens, and did not find a report for this behavior.