Guides

Troubleshooting

Common issues and solutions when using Trypema — Redis connectivity, validation errors, runtime issues, and more.

Redis connection errors

If you see TrypemaError::RedisError with connection-related messages:

  1. Check Redis is running and accessible:
redis-cli ping
# Should respond: PONG
  1. Check Redis version (must be >= 7.2):
redis-cli INFO server | grep redis_version
  1. Check your connection URL -- make sure it matches what you passed to redis::Client::open().
  2. Check network accessibility -- if Redis is on a different host, ensure the port is open and there are no firewall rules blocking access.

RedisKey validation errors

If RedisKey::try_from(...) returns Err(TrypemaError::InvalidRedisKey(...)):

  • The key must be non-empty.
  • The key must be <= 255 bytes.
  • The key must not contain : (colon is used internally as a separator).
use trypema::redis::RedisKey;

// These will fail:
// RedisKey::try_from("".to_string())          // empty
// RedisKey::try_from("user:123".to_string())  // contains ':'

// This works:
let key = RedisKey::try_from("user_123".to_string()).unwrap();

Configuration validation errors

Many configuration types are validated newtypes. Common failures:

TypeValidationError
RateLimit::try_from(value)Must be > 0.0InvalidRateLimit
WindowSizeSeconds::try_from(value)Must be >= 1InvalidWindowSizeSeconds
RateGroupSizeMs::try_from(value)Must be >= 1InvalidRateGroupSizeMs
HardLimitFactor::try_from(value)Must be >= 1.0InvalidHardLimitFactor
SuppressionFactorCacheMs::try_from(value)Must be >= 1InvalidSuppressionFactorCacheMs
SyncIntervalMs::try_from(value)Must be >= 1InvalidRateGroupSizeMs

All of these return TrypemaError variants and can be handled with ? or match.

Cleanup loop does not seem to run

With redis-tokio

Redis cleanup is spawned on the current Tokio runtime via Handle::try_current(). If there is no active Tokio runtime when you call run_cleanup_loop(), Redis cleanup will not start (a warning is logged).

Fix: Call run_cleanup_loop() from within an async context where a Tokio runtime is active.

With redis-smol

The cleanup task is a detached Smol task. It only makes progress if your application drives a Smol executor (e.g., smol::block_on(...)).

Without Redis features

Local cleanup uses a background std::thread. It should always work unless the thread fails to spawn.

Rate limits not being enforced as expected

Sticky rate limits

Remember that rate limits are sticky: the first inc() call for a key stores the rate limit. Subsequent calls for the same key ignore the rate_limit argument. If you are passing different rate limits for the same key, only the first one takes effect.

Fix: Use a consistent rate limit for each key. If you need to change a key's limit, let the old entry expire or be cleaned up.

Best-effort concurrency

Under high concurrency, multiple threads can observe "allowed" simultaneously and all proceed, causing temporary overshoot. This is by design for performance. If you need strict serialisation, use external synchronization (e.g., per-key mutexes).

Suppressed strategy: Rejected never appears

The suppressed strategy never returns Rejected. Over the hard limit, it returns Suppressed { is_allowed: false, suppression_factor: 1.0 }. If you are matching on Rejected in a suppressed context, you will never hit that arm.

Redis keys look wrong in Redis CLI

Trypema uses a structured key schema. Each user key expands into multiple Redis keys:

{prefix}:{user_key}:{rate_type}:{suffix}

For example, user_123 with the absolute strategy and default prefix creates:

trypema:user_123:absolute:h
trypema:user_123:absolute:a
trypema:user_123:absolute:w
trypema:user_123:absolute:t

This is expected. See Redis Provider for the full data model.

Hybrid provider: decisions lag behind Redis

The hybrid provider serves decisions from local state and syncs to Redis every sync_interval_ms. This means decisions may be based on stale state for up to sync_interval_ms.

Fix: Reduce sync_interval_ms for fresher state (at the cost of more Redis writes). Or use the pure Redis provider if real-time accuracy is critical.

Multi-instance configuration mismatch

If different instances use different values for window_size_seconds, rate_group_size_ms, hard_limit_factor, or suppression_factor_cache_ms, rate limiting behaviour will be inconsistent. The first instance to create a key stores the window limit in Redis; other instances will use that stored value, but their local calculations may differ.

Fix: Keep all configuration options identical across all instances.

Error types reference

ErrorCause
TrypemaError::RedisError(...)Redis connectivity or command failure.
TrypemaError::InvalidRateLimit(...)Rate limit value <= 0.
TrypemaError::InvalidWindowSizeSeconds(...)Window size < 1.
TrypemaError::InvalidRateGroupSizeMs(...)Rate group size == 0.
TrypemaError::InvalidHardLimitFactor(...)Hard limit factor < 1.0.
TrypemaError::InvalidRedisKey(...)Redis key empty, > 255 bytes, or contains :.
TrypemaError::InvalidSuppressionFactorCacheMs(...)Suppression factor cache == 0.
TrypemaError::UnexpectedRedisScriptResult(...)Lua script returned unexpected result (likely a bug -- please report).
TrypemaError::CustomError(...)Internal error.

Next steps