gofiber/fiber · error

csrf: failed to store key %q: %w

Error message

csrf: failed to store key %q: %w

What it means

Thrown at middleware/csrf/storage_manager.go:60 by storageManager.setRaw when m.storage.SetWithContext fails. This is the inner layer wrapped by error 151 (csrf: failed to store token in storage); the wrapped %w is the raw driver write error.

Source

Thrown at middleware/csrf/storage_manager.go:60

		return raw, nil
	}

	if value := m.memory.Get(key); value != nil {
		raw, ok := value.([]byte)
		if !ok {
			return nil, fmt.Errorf("csrf: unexpected value type %T in storage", value)
		}
		return raw, nil
	}

	return nil, nil
}

// set data to storage or memory
func (m *storageManager) setRaw(ctx context.Context, key string, raw []byte, exp time.Duration) error {
	if m.storage != nil {
		if err := m.storage.SetWithContext(ctx, key, raw, exp); err != nil {
			return fmt.Errorf("csrf: failed to store key %q: %w", m.logKey(key), err)
		}
		return nil
	}

	m.memory.Set(key, raw, exp)
	return nil
}

// delete data from storage or memory
func (m *storageManager) delRaw(ctx context.Context, key string) error {
	if m.storage != nil {
		if err := m.storage.DeleteWithContext(ctx, key); err != nil {
			return fmt.Errorf("csrf: failed to delete key %q: %w", m.logKey(key), err)
		}
		return nil
	}

	m.memory.Delete(key)

View on GitHub (pinned to 9a4c7e57fe)

Solutions

  1. Resolve the backend write refusal identified in the wrapped error (capacity, auth, timeout).
  2. Ensure storage capacity matches the IdleTimeout-bounded working set of CSRF tokens.
  3. Tune the storage write timeout below the per-request deadline to avoid ctx-cancellation errors.
  4. Provide cfg.ErrorHandler that returns 503 + Retry-After so clients retry cleanly.
  5. Run with cfg.Session to leverage the session store's resilience for token persistence.

Example fix

// before
app.Use(csrf.New(csrf.Config{ Storage: redis.New() }))

// after: explicit timeout + clear failure mode
store := redis.New(redis.Config{
    URL:          os.Getenv("CSRF_REDIS_URL"),
    WriteTimeout: 500 * time.Millisecond,
})
app.Use(csrf.New(csrf.Config{
    Storage: store,
    ErrorHandler: func(c fiber.Ctx, err error) error {
        if strings.Contains(err.Error(), "failed to store key") {
            c.Set(fiber.HeaderRetryAfter, "5")
            return c.Status(fiber.StatusServiceUnavailable).
                SendString("token store busy; retry shortly")
        }
        return c.Status(fiber.StatusForbidden).SendString(err.Error())
    },
}))
Defensive patterns

Strategy: try-catch

Validate before calling

// At boot, confirm the CSRF store accepts writes with the dummy payload size.
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
if err := store.SetWithContext(ctx, "__csrf_probe__", []byte("+"), time.Minute); err != nil {
    log.Fatalf("csrf storage write probe failed: %v", err)
}

Try / catch

if err := m.storage.SetWithContext(ctx, key, raw, exp); err != nil {
    return fmt.Errorf("csrf: failed to store key %q: %w", m.logKey(key), err)
}
// Caller (csrf.New) wraps via cfg.ErrorHandler into a 503 + Retry-After.

Prevention

When it happens

Trigger: CSRF token create/extend calls Storage.SetWithContext and the backend rejects the write: OOM, disk full, connection lost, ctx cancelled, auth expired.

Common situations: Redis maxmemory-policy returning errors; persistent backend out of disk; storage AUTH expired mid-run; client disconnect causing ctx cancellation during SET; network blip.

Related errors


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