{"record":{"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":500,"severity":"info","filePath":"middleware/cache/utils.go","lineNumber":23,"sourceCode":"\t\"encoding/binary\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gofiber/fiber/v3\"\n\t\"github.com/gofiber/fiber/v3/internal/fieldname\"\n\t\"github.com/gofiber/fiber/v3/internal/mediatype\"\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":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/middleware/cache/utils.go#L5-L41","documentation":"Wrapped by cacheBodyFetchError specifically around errCacheMiss: it converts the sentinel cache miss into a descriptive error naming the (masked) key. This is not a fault — it is the normal 'no cached body for this key' signal, and is the expected control-flow outcome for cache misses on the body-fetch path.","triggerScenarios":"Produced whenever the cache attempts to fetch a stored body and the underlying manager returns errCacheMiss (key absent in storage/memory, or storage returned nil bytes). Triggered on every genuine cache miss where the body is requested separately.","commonSituations":"Normal first request to an uncached route; entry expired/TTL'd out; cold start with empty cache; after explicit cache purge. Should be treated as a hit/miss signal, not an operational error.","solutions":["Detect this case with errors.Is(err, errCacheMiss) and treat it as a miss (proceed to handler), not as an error.","Do not log it at error level — log at debug/trace or not at all.","Verify the cache key/namespace and expiration are configured as expected if misses are unexpectedly high.","Confirm Storage connectivity if misses persist where hits were expected (a separate storage error would surface as 141/144 instead)."],"exampleFix":"// before: treating the wrapped miss as an error\nif err := fetchBody(); err != nil {\n    return err // wrongly fails the request on a normal miss\n}\n\n// after: unwrap and branch on the sentinel\nif err := fetchBody(); err != nil {\n    if errors.Is(err, errCacheMiss) {\n        // proceed to handler — this is a cache miss, not a fault\n    } else {\n        return err\n    }\n}","handlingStrategy":"fallback","validationCode":"// Distinguish a miss from a real error before branching.\nfunc isCacheMiss(err error) bool {\n    return errors.Is(err, errCacheMiss)\n}","typeGuard":null,"tryCatchPattern":"// This is control flow, not an error.\nif err := fetchCachedBody(); err != nil {\n    if errors.Is(err, errCacheMiss) {\n        // proceed to handler — normal miss\n        return handler(c)\n    }\n    return err // genuine storage error\n}","preventionTips":["Branch on errors.Is(err, errCacheMiss) — never log it at error level.","Expect misses on cold starts and after cache purge; they are normal.","Track hit/miss ratios to detect unexpectedly high misses (likely a separate storage error)."],"tags":["cache","cache-miss","control-flow","expected","go","fiber"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}