{"id":"3d17d41087a22d6f","repo":"gofiber/fiber","slug":"csrf-failed-to-delete-token-from-storage-w","errorCode":null,"errorMessage":"csrf: failed to delete token from storage: %w","messagePattern":"csrf: failed to delete token from storage: %w","errorType":"http","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"middleware/csrf/csrf.go","lineNumber":294,"sourceCode":"// createOrExtendTokenInStorage creates or extends the token in the storage\nfunc createOrExtendTokenInStorage(c fiber.Ctx, token string, cfg *Config, sessionManager *sessionManager, storageManager *storageManager) error {\n\tif cfg.Session != nil {\n\t\tsessionManager.setRaw(c, token, dummyValue, cfg.IdleTimeout)\n\t\treturn nil\n\t}\n\tif err := storageManager.setRaw(c, token, dummyValue, cfg.IdleTimeout); err != nil {\n\t\treturn fmt.Errorf(\"csrf: failed to store token in storage: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc deleteTokenFromStorage(c fiber.Ctx, token string, cfg *Config, sessionManager *sessionManager, storageManager *storageManager) error {\n\tif cfg.Session != nil {\n\t\tsessionManager.delRaw(c)\n\t\treturn nil\n\t}\n\tif err := storageManager.delRaw(c, token); err != nil {\n\t\treturn fmt.Errorf(\"csrf: failed to delete token from storage: %w\", err)\n\t}\n\treturn nil\n}\n\n// Update CSRF cookie\n// if expireCookie is true, the cookie will expire immediately\nfunc updateCSRFCookie(c fiber.Ctx, cfg *Config, token string) {\n\tsetCSRFCookie(c, cfg, token, cfg.IdleTimeout)\n}\n\nfunc expireCSRFCookie(c fiber.Ctx, cfg *Config) {\n\tsetCSRFCookie(c, cfg, \"\", -time.Hour)\n}\n\nfunc setCSRFCookie(c fiber.Ctx, cfg *Config, token string, expiry time.Duration) {\n\tcookie := &fiber.Cookie{\n\t\tName:        cfg.CookieName,\n\t\tValue:       token,","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/middleware/csrf/csrf.go#L276-L312","documentation":"Thrown at middleware/csrf/csrf.go:294 by deleteTokenFromStorage() when storageManager.delRaw fails. This path runs for SingleUseToken mode (consuming the token after one unsafe request) and on explicit Handler.DeleteToken. A failed DELETE means the storage backend rejected the operation.","triggerScenarios":"SingleUseToken is enabled and the post-validation DELETE hits a failing Storage backend; or Handler.DeleteToken is called and the storage is down/ACL-restricted/timed out.","commonSituations":"Storage replica in read-only mode during failover; ACLs that grant SET but not DELETE; backend OOM; ctx cancellation; network blip during the DELETE.","solutions":["Check the wrapped driver error and fix the backend cause (read-only mode, ACLs, capacity, timeout).","Grant the storage user DELETE permission in addition to GET/SET.","Since CSRF tokens are TTL-bounded by IdleTimeout, log delete failures and let the TTL reclaim the token rather than failing the user request.","If SingleUseToken reliability is critical, choose a storage backend with stronger consistency and retry semantics.","Tune the storage write timeout to fit the request deadline."],"exampleFix":"// before: single-use token failure surfaces as 500\napp.Use(csrf.New(csrf.Config{\n    Storage:        redis.New(),\n    SingleUseToken: true,\n}))\n\n// after: log + degrade; IdleTimeout reclaims the token anyway\napp.Use(csrf.New(csrf.Config{\n    Storage:        redis.New(),\n    SingleUseToken: true,\n    IdleTimeout:    15 * time.Minute,\n    ErrorHandler: func(c fiber.Ctx, err error) error {\n        if strings.Contains(err.Error(), \"failed to delete token\") {\n            log.Printf(\"csrf token delete failed (TTL will reclaim): %v\", err)\n            return c.Next()\n        }\n        return c.Status(fiber.StatusForbidden).SendString(err.Error())\n    },\n}))","handlingStrategy":"fallback","validationCode":"// At boot, confirm DELETE is permitted (ACLs sometimes omit it).\nctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)\ndefer cancel()\n_ = store.SetWithContext(ctx, \"__csrf_del_probe__\", []byte(\"+\"), time.Minute)\nif err := store.DeleteWithContext(ctx, \"__csrf_del_probe__\"); err != nil {\n    log.Fatalf(\"csrf storage DELETE denied: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"// Best-effort delete: tokens are TTL-bounded by IdleTimeout anyway.\ncfg.ErrorHandler = func(c fiber.Ctx, err error) error {\n    if strings.Contains(err.Error(), \"failed to delete token\") {\n        log.Printf(\"csrf delete failed (TTL reclaims): %v\", err)\n        return c.Next()\n    }\n    return c.Status(fiber.StatusForbidden).SendString(err.Error())\n}","preventionTips":["Grant DELETE permission to the storage user.","Never point CSRF at a read-only replica; use the writable primary.","Rely on IdleTimeout TTL as the safety net for failed deletes.","Log delete failures distinctly to catch ACL/failover drift early."],"tags":["csrf","storage","network","security","fiber"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}