{"id":"ad96a526728d67c5","repo":"gofiber/fiber","slug":"cache-no-cached-body-for-key-q-w","errorCode":null,"errorMessage":"cache: no cached body for key %q: %w","messagePattern":"cache: no cached body for key %q: %w","errorType":"http","errorClass":null,"httpStatus":null,"severity":"info","filePath":"middleware/cache/utils.go","lineNumber":19,"sourceCode":"package cache\n\nimport (\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gofiber/fiber/v3\"\n\t\"github.com/gofiber/utils/v2\"\n\t\"github.com/valyala/fasthttp\"\n)\n\nfunc cacheBodyFetchError(mask func(string) string, key string, err error) error {\n\tif errors.Is(err, errCacheMiss) {\n\t\treturn fmt.Errorf(\"cache: no cached body for key %q: %w\", mask(key), err)\n\t}\n\treturn err\n}\n\nfunc cachedResponseAge(e *item, now uint64) uint64 {\n\tclampedDate := clampDateSeconds(e.date, now)\n\n\tresident := uint64(0)\n\tif e.exp != 0 {\n\t\tif e.exp <= now {\n\t\t\tresident = e.ttl + (now - e.exp)\n\t\t} else {\n\t\t\tresident = e.ttl - (e.exp - now)\n\t\t}\n\t}\n\n\tdateAge := uint64(0)\n\tif clampedDate != 0 && now > clampedDate {","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/middleware/cache/utils.go#L1-L37","documentation":"Thrown by cacheBodyFetchError() at middleware/cache/utils.go:19 when the wrapped error is exactly errCacheMiss - i.e. there is no cached body for the requested key. This is NOT a fault: it is the sentinel used to distinguish 'cache miss for body' from a genuine storage failure. It signals a cold/expired/evicted entry rather than a backend problem.","triggerScenarios":"A body-fetch helper is invoked for a key that was never cached, was evicted by the storage backend's LRU/TTL, or expired between the metadata hit and the body fetch.","commonSituations":"First request after a deploy (cold cache); entry TTL elapsed; Redis evicted the key under memory pressure; cache namespace changed so old keys no longer resolve.","solutions":["Treat this error as a soft miss, not an error: fetch from the origin and repopulate the cache.","If misses are frequent, raise the cache TTL or increase storage capacity to reduce eviction.","Warm the cache after deploys for hot keys to avoid cold-start misses.","Confirm the key you are fetching was actually written (same CacheModifier / prefix as the write path)."],"exampleFix":"// before: treating the miss as an error\nraw, err := m.getRaw(ctx, key)\nif err != nil { return err }\n\n// after: distinguish miss from real failure\nraw, err := m.getRaw(ctx, key)\nif errors.Is(err, errCacheMiss) {\n    // cold cache - regenerate the body and store it\n    raw = computeBody()\n    _ = m.setRaw(ctx, key, raw, ttl)\n} else if err != nil {\n    return err\n}","handlingStrategy":"fallback","validationCode":"// Before fetching the body, accept that a miss is the common case.\n// No pre-check is possible; treat errCacheMiss as a signal to repopulate.","typeGuard":"// Distinguish a soft miss from a hard storage failure.\nfunc isCacheMiss(err error) bool {\n    return errors.Is(err, errCacheMiss)\n}","tryCatchPattern":"raw, err := m.getRaw(ctx, key)\nif errors.Is(err, errCacheMiss) {\n    // cold cache - regenerate, store, and return\n    raw = computeBody()\n    _ = m.setRaw(ctx, key, raw, ttl)\n} else if err != nil {\n    return err // genuine storage failure, not a miss\n}","preventionTips":["Treat errCacheMiss as expected, not as an error.","Warm hot keys after deploys to reduce cold-start misses.","Size storage/TTL to your working set to keep misses low.","Ensure the write and read paths use the same CacheModifier/prefix."],"tags":["cache","miss","fiber"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}