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 int64View on GitHub (pinned to 24529f1404)
Solutions
- Treat it as a cache miss: fetch from the backing store and populate the cache (errors.Is(err, cache.ErrKeyNotFound))
- Verify the key format matches the one used when storing (logging the exact key helps)
- Check that the cache instance/namespace used for Set is the same one used for Get
- 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
- Centralize key building in one helper to avoid key-format drift
- Make Delete idempotent by ignoring ErrKeyNotFound
- Warm caches on startup for known hot keys
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
- ErrItemExpired
- agent: StreamAsk unsupported by implementation
- agent: ResumeStreamAsk unsupported by implementation
- agent: ResumeStreamAsk requires a checkpoint
- agent: checkpointed run not found
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/3748126e12e47ab5.
Report an issue: GitHub.