{"record":{"id":"61348fe4e05fa5cc","repo":"flipped-aurora/gin-vue-admin","slug":"gva-cache","errorCode":null,"errorMessage":"GVA_CACHE 未初始化","messagePattern":"GVA_CACHE 未初始化","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/utils/captcha/cache_store.go","lineNumber":30,"sourceCode":"const defaultCaptchaExpiration = time.Second * 180\n\ntype CacheStore struct {\n\tExpiration time.Duration\n\tPreKey     string\n}\n\n// NewCacheStore 返回一个基于 GVA_CACHE 的验证码存储，前缀隔离避免与其它缓存键冲突。\nfunc NewCacheStore() *CacheStore {\n\treturn &CacheStore{\n\t\tExpiration: defaultCaptchaExpiration,\n\t\tPreKey:     \"CAPTCHA_\",\n\t}\n}\n\n// Set 写入验证码答案，按 Expiration 过期。GVA_CACHE 未就绪时返回错误，由上层(Generate)优雅处理。\nfunc (cs *CacheStore) Set(id string, value string) error {\n\tif global.GVA_CACHE == nil {\n\t\treturn errors.New(\"GVA_CACHE 未初始化\")\n\t}\n\tglobal.GVA_CACHE.Set(cs.PreKey+id, value, cs.Expiration)\n\treturn nil\n}\n\n// Get 读取验证码答案，clear=true 时读取后删除。未命中或类型不符返回空串。\nfunc (cs *CacheStore) Get(id string, clear bool) string {\n\tif global.GVA_CACHE == nil {\n\t\treturn \"\"\n\t}\n\tkey := cs.PreKey + id\n\tv, ok := global.GVA_CACHE.Get(key)\n\tif !ok {\n\t\treturn \"\"\n\t}\n\tif clear {\n\t\tglobal.GVA_CACHE.Delete(key)\n\t}","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/utils/captcha/cache_store.go#L12-L48","documentation":"CacheStore.Set writes a captcha answer into the global GVA_CACHE with the store's key prefix and expiration. If the global cache singleton was never initialized (global.GVA_CACHE == nil), it refuses to write and returns this error; the caller (captcha Generate) is expected to degrade gracefully rather than panic.","triggerScenarios":"Calling captcha Generate/Set before cache initialization has run, or in contexts where server/initialize never assigned global.GVA_CACHE (e.g. minimal test harness, tool binaries, or a config that skips cache init).","commonSituations":"Unit tests that exercise captcha code without testutil.InitMemoryCache; CLI/migration binaries that import utils but never run initialize; deployment configs where cache init failed silently at startup.","solutions":["Initialize the cache at startup so global.GVA_CACHE is non-nil (server/initialize path), then retry the captcha operation.","In tests, use testutil.InitMemoryCache(t, 0) from server/internal/testutil before calling captcha code.","If the environment intentionally has no cache, treat the error upstream: Generate handles it gracefully; avoid calling Set directly and surface a 'captcha unavailable' response."],"exampleFix":"// before\ncs := &utils.CacheStore{...}\nerr := cs.Set(id, val) // panic-free but errors: GVA_CACHE 未初始化\n// after\nfunc TestCaptcha(t *testing.T) {\n    testutil.InitMemoryCache(t, 0)\n    err := cs.Set(id, val) // GVA_CACHE now set\n}","handlingStrategy":"try-catch","validationCode":"if global.GVA_CACHE == nil {\n    // cache not ready; skip captcha or init first\n    testutil.InitMemoryCache(t, 0) // in tests\n}","typeGuard":"func cacheReady() bool { return global.GVA_CACHE != nil }","tryCatchPattern":"if err := cs.Set(id, value); err != nil {\n    // degrade gracefully: captcha generation unavailable\n    log.Warn(\"captcha disabled: %v\", err)\n    return captchaImage{}, nil // caller treats as no-captcha mode\n}","preventionTips":["Always run the standard server initialize chain (which sets GVA_CACHE) before serving requests","Use testutil.InitMemoryCache in tests instead of touching captcha code with a nil cache","Add a startup assertion/log if GVA_CACHE is nil so misconfiguration is visible early"],"tags":["captcha","cache","go","initialization"],"backgroundTag":"missing-global-singleton-init","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}