Redis OOM command not allowed: Set maxmemory-policy A developer reproduced Redis's "OOM command not allowed" error on Redis 8.10.2 with redis-py 8.1.0 and Python 3.14.4, finding that the default noeviction policy rejected the 15,201st SET while reads and deletes kept working. Testing showed allkeys-lru accepted all 60,000 writes but silently evicted a 3,000-item jobs list, while volatile-lru with a TTL on every cache key accepted all 60,000 writes and preserved the list. The developer recommends allkeys-lru only for instances holding nothing that cannot be recomputed, and volatile-lru plus TTLs otherwise. If Redis is only a cache, run redis-cli CONFIG SET maxmemory-policy allkeys-lru and put the same setting in redis.conf or your managed service's parameter group : writes go through again, because Redis now evicts least recently used keys instead of refusing new ones. If the instance also holds queues, sessions or locks, keep volatile-lru and write every cache key with a TTL SET key value EX 3600 , because the volatile policies can only evict keys that have one. This story was written with the assistance of an AI writing program. I reproduced the error on Redis 8.10.2 with redis-py 8.1.0 and Python 3.14.4, with maxmemory at 20 MB and 1 KiB values so the instance fills in seconds. Every number below comes from those runs. Under the default policy, noeviction , the 15,201st SET failed. redis-py raised redis.exceptions.OutOfMemoryError: command not allowed when used memory 'maxmemory'. ; redis-cli prints the same text after OOM . evicted keys was 0. Not every command failed. GET , EXISTS , EXPIRE and DEL still worked; SET , INCR and LPUSH were refused. Redis rejects commands that can grow memory and lets reads and deletes through, so the outage looks partial: cache reads keep hitting while writes, counters and job enqueues fail. Deleting 1,000 keys let the next SET in. Batches split too. A MULTI / EXEC with EXPIRE , SET and INCR was rejected whole, EXPIRE included. The same three commands in a plain pipeline applied the EXPIRE and failed the other two. Self-hosted Redis defaults to noeviction ; managed services often default to volatile-lru . I switched to volatile-lru and refilled with keys that had no TTL. The 15,200th SET failed with the same error and nothing was evicted: the volatile policies only choose among keys with an expiry, and there were none. Four commands show it: bash $ redis-cli CONFIG GET maxmemory-policy maxmemory-policy volatile-lru $ redis-cli INFO keyspace Keyspace db0:keys=15199,expires=0,avg ttl=0,subexpiry=0 $ redis-cli INFO stats | grep evicted keys evicted keys:0 $ redis-cli SET probe 1 OOM command not allowed when used memory 'maxmemory'. expires=0 next to thousands of keys means the policy has nothing to evict. With ex=3600 on every write, the same instance accepted 60,000 of 60,000 writes, evicted 45,155 keys and kept 14,845. Under allkeys-lru with no TTLs, all 60,000 writes succeeded and 44,863 keys were evicted. None of the first 1,000 keys written were left; 982 of the last 1,000 were. For a pure cache, that is the behavior you want. Then I put a 3,000-item list named jobs on the instance before the cache writes, the way small apps share one Redis between a task queue and a cache. Under allkeys-lru every cache write succeeded and the list was gone: EXISTS jobs returned 0, and nothing raised an error. Under volatile-lru with a TTL on each cache key, all 60,000 cache writes succeeded and the list kept its 3,000 items. Under noeviction the list survived, but cache writes failed after 12,489. allkeys-lru belongs on an instance that holds nothing you cannot recompute. Anything else gets volatile-lru plus TTLs, or better, its own instance. This is the write path I tested: python import redis r = redis.Redis host="localhost", port=6379 def cache set key, value, ttl=3600 : try: r.set key, value, ex=ttl a TTL makes the key evictable under volatile-lru except redis.exceptions.OutOfMemoryError: return False full and nothing evictable: skip the cache, keep serving return True I ran it unchanged against a local Redis on port 6379. On a fresh volatile-lru instance it returned True 60,000 times out of 60,000 while Redis evicted 45,135 keys. On a full instance whose 15,199 existing keys had no TTL, it returned False 2,000 times out of 2,000: requests were still served, but nothing new was cached. The except keeps the app up, so count those False returns and alert on them. On a full noeviction instance, CONFIG SET maxmemory-policy allkeys-lru took effect at once: the next 2,000 cache writes succeeded, with 2,051 evictions. A CONFIG SET is lost on restart, so persist the change in the config too. If the instance has to stay on volatile-lru , you can add TTLs while it is full, because EXPIRE is not refused. I set a 600-second TTL on 3,000 keys that had none; all 3,000 calls succeeded, and the next 2,000 writes went through with 2,092 evictions. In production that is a SCAN over the cache key pattern with an EXPIRE per match. With 12,000 keys, used memory was 16,744,312 bytes, about 16 of the 20 MB. One 8 MB SET was still refused under noeviction , and used memory was below the limit before and after. My reading is that the 8 MB argument is already in Redis's memory when it checks the limit, so the request counts against itself. Under allkeys-lru the same write succeeded after 4,794 evictions, and used memory read 22,416,912 bytes right after, above the 20,971,520 limit. maxmemory is a target Redis evicts toward, not a hard cap, so leave headroom below the container or VM limit. CONFIG GET maxmemory-policy and INFO keyspace first. noeviction , or a volatile- policy with expires=0 , means Redis has nothing it may evict. allkeys-lru , persisted in config, not only set at runtime. volatile-lru and a TTL on every cache write, or separate instances. maxmemory or less data, not a policy. OutOfMemoryError on cache writes and alert on it; reads keep working, so the outage looks partial. MULTI when writes must land together; a plain pipeline can apply half of them.