apache/answer · warning
captcha not exist
Error message
captcha not exist
What it means
Returned by GetCaptcha when the cache holds no value for the given key: Cache.GetString reports exist=false and the repo converts that into this error. Captcha values are stored with a TTL, so a missing entry usually means the captcha expired or the key was deleted/never set.
Source
Thrown at internal/repo/captcha/captcha.go:106
}
// SetCaptcha set captcha to cache
func (cr *captchaRepo) SetCaptcha(ctx context.Context, key, captcha string) (err error) {
err = cr.data.Cache.SetString(ctx, key, captcha, 6*time.Minute)
if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return
}
// GetCaptcha get captcha from cache
func (cr *captchaRepo) GetCaptcha(ctx context.Context, key string) (captcha string, err error) {
captcha, exist, err := cr.data.Cache.GetString(ctx, key)
if err != nil {
return "", err
}
if !exist {
return "", fmt.Errorf("captcha not exist")
}
return captcha, nil
}
func (cr *captchaRepo) DelCaptcha(ctx context.Context, key string) (err error) {
err = cr.data.Cache.Del(ctx, key)
if err != nil {
log.Debug(err)
}
return nil
}
View on GitHub (pinned to 3b9f137061)
Solutions
- Return a 'captcha expired, please refresh' response to the user instead of a 500, and issue a new captcha.
- Increase the captcha TTL in cache configuration if it expires too quickly for real users.
- Verify all app instances share the same Redis/cache backend.
- Deliver the same cache key used at SetCaptcha time (no key mangling/prefix mismatch).
Example fix
// before
captcha, exist, err := cr.data.Cache.GetString(ctx, key)
if !exist {
return "", fmt.Errorf("captcha not exist")
}
// after
captcha, exist, err := cr.data.Cache.GetString(ctx, key)
if err != nil {
return "", err
}
if !exist {
return "", ErrCaptchaExpired // caller maps to 4xx 'captcha expired, refresh'
} Defensive patterns
Strategy: try-catch
Validate before calling
// before submit: ensure a captcha was issued and is recent
if captchaKey == "" || time.Since(captchaIssuedAt) > captchaTTL {
// fetch a fresh captcha instead of verifying a stale one
return errors.New("captcha missing or likely expired, request a new one")
} Type guard
func captchaUsable(key string, issuedAt time.Time, ttl time.Duration) bool {
return key != "" && time.Since(issuedAt) < ttl
} Try / catch
answer, err := captchaRepo.GetCaptcha(ctx, key)
if err != nil {
if strings.Contains(err.Error(), "captcha not exist") {
return http.StatusBadRequest, "captcha expired, please refresh"
}
return http.StatusInternalServerError, err.Error()
} Prevention
- Set a captcha TTL comfortably longer than typical form completion time.
- Delete the captcha key only after successful verification (single-use).
- Ensure all instances point at the same Redis cache (no split backends).
- Return a user-facing 'expired' message rather than a server error.
When it happens
Trigger: Looking up a captcha by a key that was never Set, a key already consumed by DelCaptcha after verification, or one that expired from the cache.
Common situations: User takes longer than the captcha TTL to submit the form; user double-submits (first verify deletes the key); Redis restarted/flushed between issuance and verification; load-balanced deployments pointing at different cache instances.
Related errors
AI-assisted analysis of apache/answer@3b9f137061 (2026-09-05).
Data as JSON: /api/errors/d90c85c851c56178.
Report an issue: GitHub.