Guides

Troubleshooting

Common problems and what to check.

Start with these checks:

  • Confirm your RateLimit and config newtypes are valid (try_from(...) does validation).
  • For Redis provider, confirm Redis >= 6.2 and that all instances use identical provider options.
  • For suppressed decisions, always gate on is_allowed (not just the enum variant).

Redis connection refused

Check that Redis is running and reachable, and that REDIS_URL points to the right host/port.

Also check Redis version (must be >= 6.2):

Terminal
redis-cli INFO server | grep redis_version

Redis key validation fails

If you see TrypemaError::InvalidRedisKey, validate your input key:

It must be non-empty, <= 255 bytes, and must not contain :.

If you need a compound key, use a different separator like _ or |.

Validation errors when constructing types

Many configuration and input types are validated newtypes.

Common failures:

  • RateLimit::try_from(value) fails if value <= 0.
  • WindowSizeSeconds::try_from(value) fails if value < 1.
  • RateGroupSizeMs::try_from(value) fails if value < 1.
  • SuppressionFactorCacheMs::try_from(value) fails if value == 0.

Cleanup loop doesn't seem to run (Tokio)

If you're using redis-tokio, Redis cleanup is spawned on the current Tokio runtime.

Check that you're calling run_cleanup_loop() from within a Tokio runtime context, and that you haven't dropped all Arc<RateLimiter> references (cleanup uses Weak).

The cleanup loop holds a Weak<RateLimiter>, not a strong Arc. If you drop all Arc<RateLimiter> references, the loop exits by itself.

Memory usage grows over time

Check key cardinality, whether run_cleanup_loop() is enabled (local provider), and whether you need external Redis key cleanup (Redis provider).

If memory growth is attacker-driven, limit key cardinality at the edge (normalize, rate limit earlier, or require authentication).

Suppressed decisions are mishandled

If you use the suppressed strategy, RateLimitDecision::Suppressed is not automatically a denial.

Gate on is_allowed:

use trypema::RateLimitDecision;

match decision {
    RateLimitDecision::Allowed => {}
    RateLimitDecision::Suppressed { is_allowed: true, .. } => {
        // admitted (often degrade priority)
    }
    RateLimitDecision::Suppressed { is_allowed: false, .. } => {
        // suppressed: treat like denial
    }
    RateLimitDecision::Rejected { .. } => {
        // over hard limit
    }
}

If you want to admit-and-record, call inc(...) directly and use its returned decision.

Inconsistent behavior across instances

For Redis provider deployments, ensure every instance uses the same provider options:

window_size_seconds, rate_group_size_ms, hard_limit_factor, and suppression_factor_cache_ms.

Mixed configs can produce surprising admission decisions.

Redis provider doesn't compile

The Redis provider is behind feature flags.

  • Enable redis-tokio (Tokio) or redis-smol (Smol).
  • Ensure your async runtime is present and you are calling Redis methods from an async context.