Understanding the Redis 'OOM command not allowed' Error
When working with Redis in production, one of the most common and disruptive errors developers encounter is
βOOM command not allowedβ. OOM stands for Out Of Memory. This error is raised when Redis
reaches its configured maximum memory limit and is unable to serve write requests that would consume additional memory.
Redis, by default, applies a strict no-eviction policy if a maxmemory limit is set, meaning it refuses
commands that would increase memory usage instead of automatically deleting existing keys.
The error typically appears in client libraries as a Redis::CommandError (Ruby),
redis.exceptions.ResponseError (Python), or a similar exception with the message:
OOM command not allowed when used memory > 'maxmemory'
This guide walks through the root cause, diagnostic steps, immediate fixes, application-level handling, and long-term best practices to permanently resolve the error and build resilient Redis-backed systems.
What Triggers the OOM Error Exactly?
Redis manages memory using the maxmemory configuration directive. Once the used memory exceeds this limit,
Redis checks the active eviction policy. The default policy, noeviction, instructs Redis
to reject any command that could result in additional memory consumption. This includes:
- Commands that create new keys:
SET,MSET,LPUSH,SADD,ZADD, etc. - Commands that modify existing keys and increase their size:
APPEND,RPUSH(adding elements),INCRBYon a new key, etc. - Commands that load data from disk:
RESTORE,MIGRATEwith data payloads. - Administrative commands that allocate memory:
DEBUGmemory-related ops,MODULE LOADin some cases.
Read-only commands like GET, LRANGE, HGET, and EXISTS are
usually allowed even when memory is exhausted. Also, DEL and other key-deletion commands work perfectly β
they free memory, which is critical for recovery.
Why This Error Matters
An OOM error is not just a transient hiccup; it indicates that your Redis instance has hit a hard memory ceiling and cannot accept writes. For applications that rely on Redis for caching, session storage, real-time counters, or pub/sub persistence, this can lead to:
- Data loss or inconsistency β new writes fail silently (or loudly, depending on error handling), potentially leaving the dataset incomplete.
- Cascading failures β if Redis is used as a circuit-breaker or rate limiter, writes failing can cause upstream services to break.
- Increased latency β applications retry failed operations, adding load and delays.
- Inability to scale β until the memory issue is resolved, the instance cannot grow its dataset.
Understanding the OOM error is essential for anyone operating Redis as a primary data store, cache, or message broker.
Immediate Diagnostic Steps
Before applying fixes, confirm the current memory state and configuration.
1. Check Memory Usage and Limits
Connect to Redis via redis-cli and run:
INFO memory
Look for key fields:
# Memory
used_memory:2984000
used_memory_human:2.84M
used_memory_rss:5.12M
maxmemory:500000
maxmemory_human:500.00K
maxmemory_policy:noeviction
mem_allocator:jemalloc-5.1.0
If used_memory β₯ maxmemory, you're in OOM territory. Also note maxmemory_policy.
2. Verify Eviction Policy
CONFIG GET maxmemory-policy
Output will be something like:
1) "maxmemory-policy"
2) "noeviction"
If the policy is noeviction, any write exceeding maxmemory triggers the OOM error.
If you see volatile-lru or allkeys-lru, the error would only appear if there are no eligible keys
to evict (e.g., all keys have no expiry and policy is volatile-lru). We'll cover this nuance later.
3. Identify Memory Consumers
To understand what is using memory, use:
MEMORY STATS
Or the more detailed:
MEMORY DOCTOR
This will output suggestions and highlight large keys. You can also scan for biggest keys:
redis-cli --bigkeys
Often, a few excessively large strings, lists, or sets dominate memory. Client output buffers and replication
buffers can also consume significant memory β check CLIENT LIST for omem (output memory) values.
How to Fix the OOM Error: Step-by-Step Solutions
The appropriate fix depends on your use case. Below are practical approaches, from temporary mitigation to permanent resolution.
Option 1: Increase maxmemory (If Resources Allow)
If the server has spare RAM, simply raise the limit. This is the quickest fix but may only delay the problem if your data grows unbounded.
CONFIG SET maxmemory 2gb
Or update redis.conf permanently:
maxmemory 2gb
After setting, verify with CONFIG GET maxmemory. Note that increasing maxmemory doesn't evict existing keys;
it merely raises the ceiling.
Option 2: Change Eviction Policy (Allowing Automatic Key Removal)
If Redis is used purely as a cache and data loss is acceptable, switch to an evicting policy. The most common
and effective is allkeys-lru, which evicts the least recently used keys across the entire dataset
when memory is exceeded.
CONFIG SET maxmemory-policy allkeys-lru
To make it permanent, add to redis.conf:
maxmemory-policy allkeys-lru
Other policies include volatile-lru (only keys with an expiry set), allkeys-random,
volatile-ttl, etc. Choose based on whether you can afford to lose non-expiring keys.
Important: Changing the policy does not immediately evict keys; eviction only kicks in when the memory
limit is hit again. Test by temporarily lowering maxmemory to trigger eviction and observe.
After switching, monitor cache hit ratios and adjust if necessary.
Option 3: Free Up Memory by Deleting Keys or Flushing Data
If you can identify unused or expired keys, delete them manually:
DEL user:session:12345
For bulk cleanup based on pattern (use with caution in production):
redis-cli --scan --pattern 'temp:*' | xargs redis-cli DEL
If the dataset is entirely non-critical cache data, you can flush the database (reset):
FLUSHDB # for current database
FLUSHALL # for all databases
Warning: FLUSHALL is irreversible and will cause a complete cache reset, potentially
leading to a thundering herd on your backend.
Option 4: Optimize Memory Usage
Reduce per-key overhead and data sizes:
- Use shorter key names (e.g.,
u:1001instead ofuser:profile:1001). - Employ Redis data types efficiently: use hashes with
ziplistencoding for small fields, or useintsetfor integer sets. - Enable compression on large values at the application level (store as compressed byte strings).
- Set expiry (
EXPIRE) on all cache keys so they auto-delete over time. - Use
MEMORY USAGE keyto inspect individual key sizes and optimize.
Option 5: Scale Horizontally with Redis Cluster or Sharding
If a single instance cannot hold the dataset, distribute keys across multiple Redis nodes using Redis Cluster or client-side sharding. Redis Cluster automatically splits keyspace and manages failover. This eliminates the single memory bottleneck but requires application changes.
Handling the OOM Error in Application Code
Even with preventive measures, occasional memory spikes can occur. Applications must catch the error gracefully and implement fallback logic.
Python (redis-py) Example
import redis
import time
def safe_set(key, value, max_retries=3):
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
for attempt in range(max_retries):
try:
r.set(key, value)
return True
except redis.exceptions.ResponseError as e:
if 'OOM command not allowed' in str(e):
# Attempt to free memory by deleting a random expired key (if applicable)
# or simply wait and retry if eviction policy changed asynchronously
time.sleep(0.5)
continue
raise
# After max retries, fallback to alternative storage or log critical alert
return False
# Usage
success = safe_set('user:42:cart', '{"items": [...]}')
if not success:
print("Redis write failed β falling back to database")
Node.js (ioredis) Example
const Redis = require('ioredis');
const redis = new Redis();
async function safeSet(key, value, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
await redis.set(key, value);
return true;
} catch (err) {
if (err.message.includes('OOM command not allowed')) {
// Optionally delete some less important keys here
await new Promise(resolve => setTimeout(resolve, 200));
continue;
}
throw err;
}
}
return false;
}
General Retry and Circuit-Breaker Pattern
Don't retry indefinitely. Combine with exponential backoff and circuit breakers. If Redis is in OOM state, immediate retries will likely fail again. Use monitoring to trigger alerts so operations teams can intervene.
Best Practices to Avoid OOM Errors Completely
-
Always set a
maxmemorylimit β never leave it at 0 (unlimited) on production systems. Without a limit, Redis can consume all available RAM and cause OS-level OOM kills or swapping. -
Choose the right eviction policy for your workload:
allkeys-lruβ ideal for pure caches where you want to keep frequently used keys.volatile-lruβ good when non-expiring keys must never be evicted (e.g., persistent counters).noevictionβ only when Redis acts as a strict database and you have a plan for handling writes exceeding memory (like scaling out).
- Set TTLs on all cache entries β this ensures keys naturally expire, reducing memory pressure and making volatile eviction policies more effective.
-
Monitor memory usage with
used_memory_rssandmaxmemoryβ set alerts when usage exceeds 75% of maxmemory. Use tools like Redis-exporter for Prometheus, or theCONFIG SETnotifications. - Separate cache and persistent workloads β use different Redis instances with distinct policies and limits. Donβt mix mission-critical persistent keys with evictable cache data in the same database unless youβve carefully scoped the eviction policy.
-
Regularly audit memory with
MEMORY DOCTORand--bigkeysβ catch memory bloat early. - Use Redis 7 or later β newer versions offer improved memory efficiency (e.g., better hash compression, function-based scripting) and more detailed memory introspection.
- Implement application-level fallbacks β when writes fail, degrade gracefully: serve stale cached data, write to an alternative queue, or log and alert.
Advanced: Understanding Eviction Under the Hood
When the eviction policy is allkeys-lru, Redis samples a set of keys (configurable via
maxmemory-samples) and evicts the least recently used one. It repeats this process until
memory falls below the limit. This means eviction is not instant; a sudden burst of writes can still
temporarily exceed maxmemory, but the engine will quickly catch up and evict. If your application sees
a brief OOM error even with an eviction policy, it could be that all sampled keys were ineligible (e.g.,
volatile-lru with no volatile keys). In such cases, switch to allkeys-lru or ensure
sufficient volatile keys exist.
Also note that maxmemory is a soft limit for some operations. Redis uses memory for replication
buffers, client output buffers, and Lua scripts. These can push actual memory usage above maxmemory, but Redis
will still try to enforce the limit for data-bearing commands.
Conclusion
The Redis OOM command not allowed error is a protective mechanism that prevents uncontrolled
memory growth and system instability. By understanding your memory usage, setting appropriate limits, and
selecting the right eviction policy, you can eliminate this error entirely or handle it gracefully in your
application logic. Start by auditing your instance with INFO memory and MEMORY DOCTOR,
then decide whether to increase limits, switch to an eviction-based cache policy, or scale horizontally.
Finally, harden your application with retries and fallbacks to ensure that even during memory storms, your
users experience minimal disruption. With these practices, Redis remains the fast, reliable backbone it was
designed to be.