{"record":{"id":"3010c8ec51713671","repo":"gofiber/fiber","slug":"failed-to-unmarshal-response-w","errorCode":null,"errorMessage":"failed to unmarshal response: %w","messagePattern":"failed to unmarshal response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"middleware/idempotency/idempotency.go","lineNumber":76,"sourceCode":"\t// Snapshot the configured names so later mutation of the caller's slice\n\t// cannot change an already-constructed handler. Matching uses\n\t// utils.EqualFold, so no lowercased copies are needed and comparing\n\t// against the canonical-case names fasthttp reports stays allocation-free.\n\tkeepResponseHeaders := slices.Clone(cfg.KeepResponseHeaders)\n\n\tshouldKeepHeader := func(header string) bool {\n\t\treturn slices.ContainsFunc(keepResponseHeaders, func(keep string) bool {\n\t\t\treturn utils.EqualFold(header, keep)\n\t\t})\n\t}\n\n\tmaybeWriteCachedResponse := func(c fiber.Ctx, key string) (bool, error) {\n\t\tif val, err := cfg.Storage.GetWithContext(c, key); err != nil {\n\t\t\treturn false, fmt.Errorf(\"failed to read response: %w\", err)\n\t\t} else if val != nil {\n\t\t\tvar res response\n\t\t\tif _, err := res.UnmarshalMsg(val); err != nil {\n\t\t\t\treturn false, fmt.Errorf(\"failed to unmarshal response: %w\", err)\n\t\t\t}\n\n\t\t\t_ = c.Status(res.StatusCode)\n\n\t\t\tfor header, vals := range res.Headers {\n\t\t\t\tfor _, val := range vals {\n\t\t\t\t\tc.RequestCtx().Response.Header.Add(header, val)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif len(res.Body) != 0 {\n\t\t\t\tif err := c.Send(res.Body); err != nil {\n\t\t\t\t\treturn true, err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t_ = c.Locals(localsKeyIsFromCache, true)\n","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/middleware/idempotency/idempotency.go#L58-L94","documentation":"Returned by idempotency.maybeWriteCachedResponse when a stored response blob exists but fails to msgpack-unmarshal into the response struct. The wrapped %w is a msgpack decode error. It indicates the cached bytes are corrupted or were written by an incompatible schema/encoding version.","triggerScenarios":"Storage returns a non-nil blob for the idempotency key, but res.UnmarshalMsg(blob) fails — e.g. the blob was written by a different (older/newer) version of the response struct, was hand-edited, or the storage backend returned garbage due to corruption.","commonSituations":"Deploying a new version of the middleware whose msgpack-generated response schema differs, mixing data from a different serializer in the same storage key namespace, storage byte-level corruption, or a TTL collision that returns bytes from another key (rare).","solutions":["Flush the idempotency storage after middleware upgrades that change the response schema.","Namespace keys by version (KeyHeader or a key prefix) so schemas do not collide.","Inspect a sample blob to confirm it is msgpack-encoded and matches the expected fields.","If using Redis, check for key collisions or migration tooling that rewrote values."],"exampleFix":"// before\nStorage: redis.New(redis.Config{Key: \"idem:\"})\n// after — version-prefixed keys on upgrade\nKeyHeader: \"X-Idempotency-Key\"\n// and bump a key prefix in storage to invalidate old blobs\nStorage: redis.New(redis.Config{Key: \"idem-v2:\"})","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Flush the idempotency keyspace after middleware/schema upgrades.","Namespace keys by schema version to avoid collisions.","Verify a sample cached blob is valid msgpack before rolling back."],"tags":["idempotency","msgpack","serialization","schema-migration"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}