{"record":{"id":"677869483f33b176","repo":"gofiber/fiber","slug":"failed-to-write-cached-response-while-locked-w","errorCode":null,"errorMessage":"failed to write cached response while locked: %w","messagePattern":"failed to write cached response while locked: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"middleware/idempotency/idempotency.go","lineNumber":136,"sourceCode":"\t\t// First-pass: if the idempotency key is in the storage, get and return the response\n\t\tif ok, err := maybeWriteCachedResponse(c, key); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to write cached response at fastpath: %w\", err)\n\t\t} else if ok {\n\t\t\treturn nil\n\t\t}\n\n\t\tif err := cfg.Lock.Lock(key); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to lock: %w\", err)\n\t\t}\n\t\tdefer func() {\n\t\t\tif err := cfg.Lock.Unlock(key); err != nil {\n\t\t\t\tlog.Errorf(\"[IDEMPOTENCY] failed to unlock key %q: %v\", maskKey(key), err)\n\t\t\t}\n\t\t}()\n\n\t\t// Lock acquired. If the idempotency key now is in the storage, get and return the response\n\t\tif ok, err := maybeWriteCachedResponse(c, key); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to write cached response while locked: %w\", err)\n\t\t} else if ok {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Execute the request handler\n\t\tif err := c.Next(); err != nil {\n\t\t\t// If the request handler returned an error, return it and skip idempotency\n\t\t\treturn err\n\t\t}\n\n\t\t// Construct response\n\t\tres := &response{\n\t\t\tStatusCode: c.Response().StatusCode(),\n\t\t\tBody:       c.Response().Body(),\n\t\t}\n\t\t{\n\t\t\theaders := make(map[string][]string)\n\t\t\tif err := c.Bind().RespHeader(headers); err != nil {","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/middleware/idempotency/idempotency.go#L118-L154","documentation":"Wraps an error from maybeWriteCachedResponse when re-checking the cache after acquiring the lock (double-checked locking pattern). Same underlying causes as errors 168/169 (storage read or unmarshal failure), but observed on the locked path — meaning another request may have just written or be writing the entry.","triggerScenarios":"After cfg.Lock.Lock succeeds, the second maybeWriteCachedResponse call returns an error. Common when the storage briefly failed on the fastpath (error 170) and is still failing under the lock, or when a concurrent writer produced an unparseable blob that this holder then reads.","commonSituations":"Storage outage that spans both lookups, a race where a concurrent process wrote a schema-incompatible blob, or a storage backend under heavy load returning partial/corrupt reads.","solutions":["Address the storage/marshalling root cause (errors 168/169).","If a concurrent writer is producing bad blobs, gate writes behind the same schema version.","Investigate lock-holder interactions — ensure Unlock is always called (the deferred Unlock logs but does not propagate).","Add tracing on the locked re-check path to correlate with concurrent writers."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep storage healthy across both fastpath and locked re-check.","Ensure concurrent writers share the same response schema.","Confirm Unlock always fires (deferred) to avoid lock leaks."],"tags":["idempotency","storage","double-checked-locking","context-wrap"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}