Gets fail in case of small caches

In the master branch commit 13024c7bdb7e6df119fb0d8f3bfdbfc86779b78c it is not possible to use caches with max-cost 40 or lower (num counters = max-cost * 10). Gets from smaller caches fail reliably. This limitation was not present in the latest tagged release.

This can be tested using the example code on your github page:

func main() {
	cache, err := ristretto.NewCache(&ristretto.Config{
		NumCounters: 400,
		MaxCost:     40,
		BufferItems: 64,
	if err != nil {

	// set a value with a cost of 1
	cache.Set("key", "value", 1)
	// wait for value to pass through buffers
	time.Sleep(10 * time.Millisecond)

	value, found := cache.Get("key")
	if !found {
		panic("missing value")

Thanks for the bug report @tarmo-randma (and welcome btw). This is a very interesting potential bug.

ping @ibrahim

ps: 40 bytes is a VERY small cache

Yes, I agree 40 is a very small cache. It only came up because I have built some additional functionality on top of ristretto and unit tests of that functionality in ‘cache full’ situations used small caches for simplicity.

Fortunately this is easy to work around by using a larger max-cost and cost during set.

Hey, the entry is being rejected because it doesn’t fit in the max cost. The maxCost you’ve set is 40 but the cost of the entry turns out to be 41 (we include the cost of storing it as well).

If you make the following change to your code

	cache, err := ristretto.NewCache(&ristretto.Config{
		NumCounters: 400,
		MaxCost:     40,
		BufferItems: 64,
		OnReject: func(item *ristretto.Item) {
			fmt.Printf("Rejected item = %+v\n", item)

You’ll see see that the actual cost of the item is 41

Rejected item = &{

We add the cost here

Thanks, that makes sense. I saw that new configuration parameter but assumed it defaults to backwards compatibility. Looking forward to 1.0.0 to get more hints from semver.

Anyways thanks for a great library and keep up the good work!

Issue solved. Closing topic