gofiber/fiber · error

failed to unmarshal response: %w

Error message

failed to unmarshal response: %w

What it means

Returned by maybeWriteCachedResponse (idempotency.go:75-76) when msgpack UnmarshalMsg fails on the bytes returned by Storage.Get. The cached payload is corrupted or was written by an incompatible schema version of this middleware.

Source

Thrown at middleware/idempotency/idempotency.go:76

	// Snapshot the configured names so later mutation of the caller's slice
	// cannot change an already-constructed handler. Matching uses
	// utils.EqualFold, so no lowercased copies are needed and comparing
	// against the canonical-case names fasthttp reports stays allocation-free.
	keepResponseHeaders := slices.Clone(cfg.KeepResponseHeaders)

	shouldKeepHeader := func(header string) bool {
		return slices.ContainsFunc(keepResponseHeaders, func(keep string) bool {
			return utils.EqualFold(header, keep)
		})
	}

	maybeWriteCachedResponse := func(c fiber.Ctx, key string) (bool, error) {
		if val, err := cfg.Storage.GetWithContext(c, key); err != nil {
			return false, fmt.Errorf("failed to read response: %w", err)
		} else if val != nil {
			var res response
			if _, err := res.UnmarshalMsg(val); err != nil {
				return false, fmt.Errorf("failed to unmarshal response: %w", err)
			}

			_ = c.Status(res.StatusCode)

			for header, vals := range res.Headers {
				for _, val := range vals {
					c.RequestCtx().Response.Header.Add(header, val)
				}
			}

			if len(res.Body) != 0 {
				if err := c.Send(res.Body); err != nil {
					return true, err
				}
			}

			_ = c.Locals(localsKeyIsFromCache, true)

View on GitHub (pinned to 9a4c7e57fe)

Solutions

  1. Namespace idempotency keys so they cannot collide with other Storage users (prefix the key in your KeyGenerator).
  2. After a schema-changing upgrade, flush the affected Storage keys or bump the key prefix.
  3. Investigate any non-idempotency code writing to the same Storage keyspace.

Example fix

// before — keys share namespace with other apps
KeyHeader: "X-Idempotency-Key"

// after — prefix keys so collisions are impossible
Next: nil,
// (wrap storage or use a prefixed storage adapter so all keys start with "idem:")
Defensive patterns

Strategy: validation

Validate before calling

// namespace keys to prevent collisions
KeyGenerator: func(c fiber.Ctx) string {
    return "idem:" + c.Get("X-Idempotency-Key")
}

Prevention

When it happens

Trigger: Storage holds bytes for the key that are not a msgpack-encoded response (manual write, key collision with another subsystem); an upgrade changed the response struct fields; partial writes from a crashed instance; storage backend bit-rot.

Common situations: Deploying a new version of the idempotency middleware whose response struct shape differs; two services sharing a Storage namespace and colliding on key prefixes; backup restore of stale data.

Related errors


AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04). Data as JSON: /data/errors/3010c8ec51713671.json. Report an issue: GitHub.