micro/go-micro · info

ErrKeyNotFound

ErrKeyNotFound

Error message

key not found in cache

What it means

ErrKeyNotFound is a sentinel error returned by Cache.Get and Cache.Delete when the provided key does not exist in the cache. It is the cache's way of signaling a pure miss — the key was never stored or has already been removed. Unlike ErrItemExpired, it carries no implication about TTLs.

Source

Thrown at cache/cache.go:21

import (
	"context"
	"errors"
	"time"
)

var (
	// DefaultCache is the default cache.
	DefaultCache Cache = NewCache()
	// DefaultExpiration is the default duration for items stored in
	// the cache to expire.
	DefaultExpiration time.Duration = 0

	// ErrItemExpired is returned in Cache.Get when the item found in the cache
	// has expired.
	ErrItemExpired error = errors.New("item has expired")
	// ErrKeyNotFound is returned in Cache.Get and Cache.Delete when the
	// provided key could not be found in cache.
	ErrKeyNotFound error = errors.New("key not found in cache")
)

// Cache is the interface that wraps the cache.
type Cache interface {
	// Get gets a cached value by key.
	Get(ctx context.Context, key string) (interface{}, time.Time, error)
	// Put stores a key-value pair into cache.
	Put(ctx context.Context, key string, val interface{}, d time.Duration) error
	// Delete removes a key from cache.
	Delete(ctx context.Context, key string) error
	// String returns the name of the implementation.
	String() string
}

// Item represents an item stored in the cache.
type Item struct {
	Value      interface{}
	Expiration int64

View on GitHub (pinned to 24529f1404)

Solutions

  1. Treat it as a cache miss: fetch from the backing store and populate the cache (errors.Is(err, cache.ErrKeyNotFound))
  2. Verify the key format matches the one used when storing (logging the exact key helps)
  3. Check that the cache instance/namespace used for Set is the same one used for Get
  4. For Delete, ignore ErrKeyNotFound when deletion is meant to be idempotent

Example fix

// before
if err := cache.Delete(ctx, "user:1"); err != nil { return err }
// after
if err := cache.Delete(ctx, "user:1"); err != nil && !errors.Is(err, cache.ErrKeyNotFound) {
    return err
}
Defensive patterns

Strategy: fallback

Validate before calling

if key == "" { return fmt.Errorf("empty cache key") }
// verify key matches the scheme used at Put time, e.g. "user:<id>"

Type guard

func isMiss(err error) bool { return errors.Is(err, cache.ErrKeyNotFound) }

Try / catch

v, _, err := cache.Get(ctx, key)
if errors.Is(err, cache.ErrKeyNotFound) {
    v, err = loadFromDB(ctx, key)
    if err != nil { return err }
    _ = cache.Put(ctx, key, v, ttl)
} else if err != nil { return err }

Prevention

When it happens

Trigger: Cache.Get with a key that was never set; Cache.Delete with an unknown key; Get on a key that was previously evicted or deleted by another goroutine.

Common situations: Reading a cache warmed by a different process/instance; typos or inconsistent key naming schemes (e.g. "user:1" vs "user-1"); race between expiry-eviction and a Get in high-churn caches; calling Delete for idempotent cleanup.

Related errors


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/3748126e12e47ab5. Report an issue: GitHub.