gofr-dev/gofr · warning
%w: %s
Error message
%w: %s
What it means
NATS KV Get translates nats.ErrKeyNotFound from the underlying bucket into this library's sentinel: fmt.Errorf("%w: %s", errKeyNotFound, key), producing 'key not found: <key>'. The %w wrap preserves errors.Is matching against the library's errKeyNotFound. Other KV errors take a different path ('failed to get key').
Source
Thrown at pkg/gofr/datasource/kv-store/nats/nats.go:116
Bucket: c.configs.Bucket,
})
if err != nil {
c.logger.Errorf("error while creating/accessing KV bucket: %v", err)
return
}
c.kv = kv
c.logger.Infof("successfully connected to NATS-KV Store at %s:%s ", c.configs.Server, c.configs.Bucket)
}
func (c *Client) Get(ctx context.Context, key string) (string, error) {
span := c.addTrace(ctx, "get", key)
defer c.sendOperationStats(time.Now(), "GET", "get", span, key)
entry, err := c.kv.Get(key)
if err != nil {
if errors.Is(err, nats.ErrKeyNotFound) {
return "", fmt.Errorf("%w: %s", errKeyNotFound, key)
}
return "", fmt.Errorf("failed to get key: %w", err)
}
return string(entry.Value()), nil
}
func (c *Client) Set(ctx context.Context, key, value string) error {
span := c.addTrace(ctx, "set", key)
defer c.sendOperationStats(time.Now(), "SET", "set", span, key, value)
_, err := c.kv.Put(key, []byte(value))
if err != nil {
return fmt.Errorf("failed to set key-value pair: %w", err)
}
return nilView on GitHub (pinned to 187eb24962)
Solutions
- Use errors.Is(err, errKeyNotFound) to branch on miss and provide a default/fetch-from-source path
- Verify bucket consistency between producers and consumers
- Extend the bucket TTL if legitimate keys expire
- Log the key from the message to debug naming mismatches
Example fix
// before
v, err := store.Get(ctx, key)
return v, err
// after
v, err := store.Get(ctx, key)
if errors.Is(err, kv.ErrKeyNotFound) { return loadFromDB(key) }
if err != nil { return err } Defensive patterns
Strategy: fallback
Validate before calling
// validate key format and non-emptiness before Get
if key == "" || !keyRe.MatchString(key) { return fmt.Errorf("invalid key %q", key) } Type guard
func IsKeyNotFound(err error) bool { return errors.Is(err, natskv.ErrKeyNotFound) } Try / catch
v, err := store.Get(ctx, key)
if errors.Is(err, natskv.ErrKeyNotFound) {
return loadFromSource(key) // miss path
}
if err != nil { return fmt.Errorf("get %s: %w", key, err) } Prevention
- Treat key-not-found as expected control flow, log at debug level
- Standardize key naming in a keys package
- Set TTLs deliberately and document them
- Keep miss-path latency low (local default or DB fallback)
When it happens
Trigger: c.kv.Get(key) returns nats.ErrKeyNotFound — the key has no entry in the JetStream bucket (never written, deleted, or TTL-expired).
Common situations: Expired keys (bucket MaxAge), reading keys written to another bucket, miss-heavy cache lookups, key naming typos.
Related errors
AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01).
Data as JSON: /api/errors/bef116b05fa629eb.
Report an issue: GitHub.