InletDownload

Redis error WRONGTYPE

WRONGTYPE Operation against a key holding the wrong kind of value

You ran a command for one data type on a key that holds another, such as GET on a hash. Nothing changed. Check the key with TYPE, then use that type’s commands or give the two kinds of data different key names.

WRONGTYPE Operation against a key holding the wrong kind of value

Tested on Redis 8.10.2 and Valkey 8.1.10 · Updated 9 October 2026

What it means

Every Redis key holds one type of value: a string, list, set, sorted set, hash or stream. Each command works on one type: GET and INCR on strings, HGET and HGETALL on hashes, LPUSH and LRANGE on lists, SADD and SMEMBERS on sets, ZADD and ZRANGE on sorted sets, XADD and XRANGE on streams. Run one on a key of another type and Redis refuses with WRONGTYPE. The command does nothing, and the key keeps its value.

A few things to know:

  • A missing key is never the wrong type. Read commands treat it as empty (GET replies (nil)), and write commands create it with their own type.
  • SET overwrites a key of any type. It replaces a hash or list with a string without a warning. Only SET … GET, which reads the old value first, fails with WRONGTYPE.
  • Some types are others underneath. Bitmaps and HyperLogLogs are strings, and geospatial indexes are sorted sets, so TYPE reports string and zset. A string that isn’t a HyperLogLog gets its own wording from PFADD: WRONGTYPE Key is not a valid HyperLogLog string value.
  • Inside a Lua script, the error ends with the script it came from: … script: d3c21d0c2b9ca22f82737626a27bcaf5d288f99f, on @user_script:1.

Common causes

  1. One key name used for two kinds of data. One part of your code caches a user as a JSON string under user:1; another stores the same user as a hash under the same name. Whichever writes first decides the type, and the other one fails.
  2. The wrong command for the type: GET on a hash, LRANGE on a set, HGETALL on a string.
  3. A change of format. Your code switched from JSON strings to hashes (or back), and keys written in the old format are still there until they expire or are deleted.
  4. JSON documents. On Redis 8 with its JSON data type (and Redis Stack), JSON.SET keys have the type ReJSON-RL. GET and HGETALL on them fail with WRONGTYPE; read them with JSON.GET.

How to fix it

Check the key’s type

TYPE <key>

It replies string, list, set, zset, hash, stream (or a module’s type, such as ReJSON-RL), or none if the key doesn’t exist. Then read it with that type’s commands:

TYPERead it with
stringGET, MGET, STRLEN
hashHGETALL, HGET, HMGET
listLRANGE <key> 0 -1, LLEN
setSMEMBERS, SSCAN, SISMEMBER
zsetZRANGE <key> 0 -1 WITHSCORES, ZSCORE
streamXRANGE <key> - +, XREVRANGE
ReJSON-RLJSON.GET

OBJECT ENCODING <key> shows how Redis stores the value internally (listpack, hashtable, int, raw…). It’s useful for memory questions, but it’s TYPE that decides which commands work.

Find the keys with the unexpected type

SCAN takes a TYPE filter (Redis 6 and later), so you can list, say, every user:* key that is a string when your code expects hashes:

SCAN 0 MATCH user:* TYPE string

Repeat with the cursor it returns until it comes back as 0.

Give each kind of data its own key names

Make the type part of the name, so two features can’t collide: user:1 for the hash, user:1:cache for a cached JSON string, user:1:sessions for a set.

Replace old values on purpose

If the wrong-type keys are left over from an old format, delete them (DEL or UNLINK) or let them expire, and let your code write them again in the new format. During a migration, code that can meet both formats can check TYPE first and read accordingly. Overwriting with SET works on any type, so only use it when you mean to replace the value.

Reproduce it

Redis 8.10.2, redis-cli 8.10.2, in database 15:

HSET seo:auth:user:1 name Ada email ada@example.com
(integer) 2
GET seo:auth:user:1
(error) WRONGTYPE Operation against a key holding the wrong kind of value
TYPE seo:auth:user:1
hash
OBJECT ENCODING seo:auth:user:1
"listpack"
HGETALL seo:auth:user:1
1) "name"
2) "Ada"
3) "email"
4) "ada@example.com"

LPUSH, INCR and SADD on the same hash got the same error, and so did HGET on a string, LRANGE on a stream and SMEMBERS on a sorted set. SET seo:auth:user:1 x GET failed the same way, while a plain SET on the hash replied OK and TYPE then said string. A key that didn’t exist: TYPE replied none and GET replied (nil).

PFADD on a string holding 5:

(error) WRONGTYPE Key is not a valid HyperLogLog string value.

GET on the hash from inside a script (EVAL "return redis.call('GET', KEYS[1])" 1 seo:auth:user:1):

(error) WRONGTYPE Operation against a key holding the wrong kind of value script: d3c21d0c2b9ca22f82737626a27bcaf5d288f99f, on @user_script:1.

SCAN 0 MATCH seo:auth:* TYPE hash returned only the hash among the test keys. Valkey 8.1.10 gave every message word for word.

The test server runs without Redis 8’s data-type modules, so the JSON case ran on a temporary Redis 8.10.2 server started the image’s default way, which loads them. After JSON.SET user:1 $ '{"name":"Ada"}', TYPE user:1 replied ReJSON-RL, and GET and HGETALL got WRONGTYPE. The other way round, JSON.GET on a plain string replied (error) Existing key has wrong Redis type, without the WRONGTYPE code.

In Inlet

The key grid shows each key’s type next to its TTL, size and value, so a namespace where one key differs from the rest stands out; you can also filter the grid by type. Hashes show as JSON objects, lists and sets as arrays, and sorted sets with their scores. Query tabs take redis-cli commands, so you can run TYPE and the matching read command there. When the server refuses a command, Inlet shows the message after the WRONGTYPE code and links to this page.

Related

Sources