What it means
Redis stores every string value as bytes, but some commands treat them as numbers: INCR, DECR,
INCRBY and DECRBY read the key’s value as a signed 64-bit integer, add to it and store the
result. Many commands also take numeric arguments: TTLs (EXPIRE, SET … EX), counts, list
indexes, database numbers. When either one isn’t a whole number in the range −9223372036854775808
to 9223372036854775807, Redis refuses with:
(error) ERR value is not an integer or out of range
Nothing changes: the key keeps its value.
Redis is strict about what counts as an integer. In the test below, abc, 1.5, 1e3, " 5"
(with a space), "5" stored with its double quotes, 05, +5 and even -0 were all refused,
while -5 was fine: only digits, with a - in front of a negative number, and no leading zeros.
The same family of errors:
| Message | When |
|---|---|
ERR value is not a valid float | INCRBYFLOAT, ZADD, ZINCRBY get something that isn’t a number (abc, 1,5) |
ERR increment or decrement would overflow | the result wouldn’t fit in 64 bits (DECRBY says ERR decrement would overflow) |
ERR hash value is not an integer | HINCRBY on a hash field that holds text (HINCRBYFLOAT: … is not a float) |
ERR timeout is not a float or out of range | BLPOP and the other blocking commands get a timeout that isn’t a number |
ERR increment would produce NaN or Infinity | INCRBYFLOAT by inf |
A key holding another type altogether, such as a hash, gets WRONGTYPE instead.
Common causes
INCRon a value that was written as text: a JSON-encoded number ("5"with quotes), a value with a space or a newline, or a word such asnoneornull.- A whole number written as a decimal. Code that stores a floating-point variable can send
1.0rather than1, andINCRrefuses1.0. MixingINCRBYFLOATandINCRon one key fails the same way whenever the value has a fraction:5plus0.5is5.5, whichINCRrefuses (INCRBYFLOATstores a whole result without decimals, so6works again). - A decimal argument where Redis wants a whole number:
EXPIRE k 1.5,SET k v EX 2.5,SETEX k 1.5 v,INCRBY k 1.5. A duration with a unit (60s) fails the same way. - A number past 64 bits:
INCRBY k 9223372036854775808, or a counter that has really reached the limit (that one isincrement or decrement would overflow). - Arguments in the wrong order, so a key name or value lands where a number goes:
LRANGE k 0 ten,SELECT abc,SETEX k value 60instead ofSETEX k 60 value.
How to fix it
Look at what’s stored
GET <key>
STRLEN <key>
OBJECT ENCODING <key>
A value Redis can increment shows as plain digits, and OBJECT ENCODING replies int when Redis
holds the value as a number. Quotes, spaces or a decimal point in the GET output are the
problem. STRLEN gives away invisible characters: "5" should be 1 byte long.
Write numbers as plain integers
Send whole numbers in their decimal form, without quotes, padding or .0: convert a float to an
integer before writing it, and don’t JSON-encode values that you’ll increment. If you need
fractions, use INCRBYFLOAT throughout and read with GET; don’t mix it with INCR on one key.
To repair a key that holds a bad value, overwrite it with a number (SET <key> 5) or delete it:
INCR on a key that doesn’t exist starts from 0.
Send whole-number arguments
TTLs are whole seconds (EXPIRE, EX) or whole milliseconds (PEXPIRE, PX). For 1.5 seconds,
use PEXPIRE <key> 1500 or SET <key> <value> PX 1500.
Check each argument’s position
COMMAND DOCS <command> lists the arguments in order. SETEX takes the seconds before the value;
LRANGE takes two integer indexes.
Reproduce it
Redis 8.10.2 and Valkey 8.1.10 gave identical replies to every command below, in database 15:
SET seo:err:visits abc
OK
INCR seo:err:visits
(error) ERR value is not an integer or out of range
INCR failed the same way after SET seo:err:visits to 1.5, ' 5', '"5"', 05 and +5
(and, on Redis, 1e3 and -0; -0 on Valkey too). After SET seo:err:visits 5,
INCRBY seo:err:visits 2 replied (integer) 7 and OBJECT ENCODING seo:err:visits replied
"int". On Redis, INCR took -5 to -4. Arguments:
INCRBY seo:err:visits 1.5
(error) ERR value is not an integer or out of range
EXPIRE seo:err:visits 60s
(error) ERR value is not an integer or out of range
SET seo:err:visits 1 EX 2.5
(error) ERR value is not an integer or out of range
LRANGE seo:err:visits 0 ten
(error) ERR value is not an integer or out of range
SELECT abc
(error) ERR value is not an integer or out of range
EXPIRE with 1.5 and SETEX with 1.5 got the same. Mixing float and integer increments:
SET seo:err:n 5
OK
INCRBYFLOAT seo:err:n 0.5
"5.5"
INCR seo:err:n
(error) ERR value is not an integer or out of range
INCRBYFLOAT seo:err:n 0.5
"6"
INCR seo:err:n
(integer) 7
Overflow and the float errors:
SET seo:err:max 9223372036854775807
OK
INCR seo:err:max
(error) ERR increment or decrement would overflow
INCRBY seo:err:visits 9223372036854775808
(error) ERR value is not an integer or out of range
INCRBYFLOAT seo:err:visits 1,5
(error) ERR value is not a valid float
ZADD seo:err:z abc m
(error) ERR value is not a valid float
HINCRBY seo:err:h n 1
(error) ERR hash value is not an integer
BLPOP seo:err:q abc
(error) ERR timeout is not a float or out of range
(seo:err:h held n = abc.) Inside a script, INCR on a word gave the same message with the
script’s SHA1 and line after it:
ERR value is not an integer or out of range script: 61636018f4e6b5817b89791bbed242f93fa089e3, on @user_script:1.
In Inlet
The key grid shows each key’s value and type, and you can edit a value in place, so a counter
stored as "5" or 1.0 is easy to spot and correct. Query tabs take redis-cli commands for GET,
OBJECT ENCODING and the rest. When the server refuses a command, Inlet shows its message and links
to this page.