Fix Redis 'ERR value is not an integer or out of range' on INCR and DECR Commands

beginner๐Ÿ”ด Redis2026-05-13| Redis 6.x / 7.x on Linux, macOS, Windows (WSL2) โ€” affects any client library (redis-cli, ioredis, redis-py, Jedis, go-redis)

Error Message

ERR value is not an integer or out of range
#redis#incr#decr#data-type#integer

What just happened?

You ran an INCR, INCRBY, DECR, or DECRBY command and Redis replied with:

(error) ERR value is not an integer or out of range

Redis counter commands only work when the stored value looks like a plain decimal integer โ€” no floats, no JSON blobs, no empty strings. The moment something else ends up under that key, the command stops cold.

Reproduce the error in 30 seconds

# Store a float
127.0.0.1:6379> SET page_views 3.5
OK
127.0.0.1:6379> INCR page_views
(error) ERR value is not an integer or out of range

# Store a string
127.0.0.1:6379> SET page_views "hello"
OK
127.0.0.1:6379> INCR page_views
(error) ERR value is not an integer or out of range

# Store an empty string
127.0.0.1:6379> SET page_views ""
OK
127.0.0.1:6379> INCR page_views
(error) ERR value is not an integer or out of range

# Integer too large for 64-bit signed range
127.0.0.1:6379> SET big_num 9999999999999999999999
OK
127.0.0.1:6379> INCR big_num
(error) ERR value is not an integer or out of range

Diagnose your key first

Don't touch anything yet. Start by checking exactly what's stored:

127.0.0.1:6379> TYPE your_key
string
127.0.0.1:6379> GET your_key
"3.5"
127.0.0.1:6379> STRLEN your_key
(integer) 3

These are the usual suspects:

  • A float like "1.0" or "0.5" โ€” application code serialized a number without truncating the decimal
  • A JSON blob like "{\"count\": 1}" โ€” someone stored the whole object instead of extracting the integer field
  • An empty string "" โ€” the key was initialized without a value
  • A number outside the signed 64-bit range (-9223372036854775808 to 9223372036854775807)
  • A stale key left over from an old data model, now reused for a counter

Quick fix: reset the key to a valid integer

Need the counter working immediately? Overwrite it:

# Check current value
127.0.0.1:6379> GET page_views
"3.5"

# Overwrite with the closest integer
127.0.0.1:6379> SET page_views 3
OK

# Now INCR works
127.0.0.1:6379> INCR page_views
(integer) 4

Starting from scratch? Just delete the key and call INCR directly. Redis initializes missing keys to 0 before incrementing:

127.0.0.1:6379> DEL page_views
(integer) 1
127.0.0.1:6379> INCR page_views
(integer) 1

Fix the root cause in application code

Case 1: Your code writes a float instead of an integer

Floats are the most frequent offender. Python, JavaScript, and several other languages can serialize a number like 1 as "1.0" without any warning โ€” and Redis refuses to increment it.

# Python โ€” wrong
import redis
r = redis.Redis()
r.set('page_views', 1.0)   # Stores "1.0", not "1"
r.incr('page_views')        # Boom

# Python โ€” correct
r.set('page_views', int(1.0))   # Stores "1"
r.incr('page_views')             # Works
// Node.js (ioredis) โ€” wrong
await redis.set('page_views', parseFloat('3.5'));  // Stores "3.5"

// Node.js โ€” correct
await redis.set('page_views', Math.floor(3.5));   // Stores "3"
await redis.incr('page_views');                    // Works

Case 2: You're storing a JSON object and trying to increment a field inside it

Redis strings don't support partial updates. Store the counter as a separate hash field and use HINCRBY instead:

# Store each field separately as a hash
127.0.0.1:6379> HSET user:42 page_views 10 login_count 3
(integer) 2

# Increment one field atomically
127.0.0.1:6379> HINCRBY user:42 page_views 1
(integer) 11

# Decrement
127.0.0.1:6379> HINCRBY user:42 login_count -1
(integer) 2

Case 3: Float counters โ€” use INCRBYFLOAT instead

Tracking scores, rates, or any value that needs decimal precision? Use INCRBYFLOAT. The stored value must still be numeric, but decimals are fine:

127.0.0.1:6379> SET score 10.5
OK
127.0.0.1:6379> INCRBYFLOAT score 0.5
"11"
127.0.0.1:6379> INCRBYFLOAT score 1.25
"12.25"

One gotcha: after enough INCRBYFLOAT calls, the stored value will contain a decimal point. Running plain INCR on that key later will fail. Keep float keys and integer keys separate.

Case 4: Race condition with key initialization

Two processes initializing the same key at the same time is a classic race. One writes a non-integer value; the other immediately calls INCR and hits the error. The fix is simple โ€” let INCR handle initialization itself:

# Don't do this (race condition)
IF key not exists:
    SET counter 0
INCR counter

# Do this instead โ€” INCR is atomic and initializes from 0 if key is missing
INCR counter

Verify the fix

# Check the value is a valid integer string
127.0.0.1:6379> GET page_views
"4"

# INCR should return the next integer
127.0.0.1:6379> INCR page_views
(integer) 5

# DECR should work too
127.0.0.1:6379> DECR page_views
(integer) 4

# INCRBY and DECRBY with step
127.0.0.1:6379> INCRBY page_views 10
(integer) 14
127.0.0.1:6379> DECRBY page_views 3
(integer) 11

All four work without error? The key is clean.

Add a guard in code before incrementing

Production counters deserve a safety net. This Python helper validates the stored value first, resets it if corrupted, and logs a warning so you know it happened:

# Python helper
def safe_incr(r, key):
    val = r.get(key)
    if val is not None:
        try:
            int(val)  # Will raise if not a valid integer string
        except (ValueError, TypeError):
            # Reset to 0 and log a warning
            r.set(key, 0)
            print(f"WARNING: reset corrupt counter key '{key}' (was: {val})")
    return r.incr(key)

Quick reference: which commands are affected

  • INCR key โ€” increment by 1
  • INCRBY key amount โ€” increment by amount (integer)
  • DECR key โ€” decrement by 1
  • DECRBY key amount โ€” decrement by amount (integer)

All four require the value to be a string representation of a signed 64-bit integer. INCRBYFLOAT is the one exception โ€” it accepts decimals, but mixing it with the integer commands on the same key will eventually land you back here.

Related Error Notes