Redis Error Guide: 'WRONGTYPE Operation against a key holding the wrong kind of value'
Fix WRONGTYPE errors in Redis: diagnose key-type mismatches, colliding key names, wrong command for a type, and format drift using TYPE and SCAN.
- #redis
- #troubleshooting
- #errors
- #data-types
Overview
WRONGTYPE Operation against a key holding the wrong kind of value is returned when you run a command against a key whose data type does not match the command. Redis keys are strongly typed: a key is a string, list, set, sorted set, hash, or stream, and each command family only works on its own type. Running LPUSH on a key that holds a string, or GET on a key that holds a hash, raises WRONGTYPE.
The literal error:
(error) WRONGTYPE Operation against a key holding the wrong kind of value
This is almost always an application bug, not a Redis fault: two code paths use the same key name for different types, a key was created by an older serialization format, or a command was simply issued against the wrong key. It is deterministic — the same key + command always fails until the key’s type or name changes.
Symptoms
- A specific command fails with
WRONGTYPEfor certain keys but not others. - Errors cluster around a shared key namespace (e.g.
session:*,cache:*). - A new deploy that changed a value’s structure (string → hash) triggers failures for keys written by the old code.
TYPE <key>returns a different type than the command expects.
redis-cli TYPE session:42
string
redis-cli HGETALL session:42
(error) WRONGTYPE Operation against a key holding the wrong kind of value
Common Root Causes
1. Key name collision across types
Two features use the same key. One writes a string, another expects a hash.
redis-cli TYPE user:1000
redis-cli OBJECT ENCODING user:1000
string
embstr
If one code path does SET user:1000 ... and another does HSET user:1000 ..., the second fails.
2. Wrong command for the type
Using GET/SET on a hash, SADD on a list, INCR on a non-integer string, etc.
(error) WRONGTYPE Operation against a key holding the wrong kind of value
3. Serialization/format drift after a deploy
Code that previously stored a JSON string now stores a hash (or vice versa). Keys written before the deploy keep the old type and break the new reader.
4. Key TTL/eviction masking the bug
A short TTL can hide a collision (the wrong-type key expires between failures), making WRONGTYPE appear intermittent when it is actually deterministic per key.
Diagnostic Workflow
Step 1: Identify the exact key and its actual type
Capture the failing key from the app log, then:
redis-cli TYPE <key>
redis-cli OBJECT ENCODING <key>
redis-cli TTL <key>
TYPE tells you what the key really is; compare against what the command expects.
Step 2: Find how the key was created (colliding writers)
Search the codebase for the key pattern to find every command that touches it:
# in your app repo
grep -rnE "['\"](session|user|cache):" src/ | grep -iE 'set|hset|lpush|sadd|zadd'
Look for two different type families writing the same prefix.
Step 3: Scan for keys of the unexpected type in the namespace
# Never use KEYS in production; SCAN is non-blocking
redis-cli --scan --pattern 'session:*' | while read k; do
printf '%s %s\n' "$(redis-cli TYPE "$k")" "$k"
done | sort | uniq -c | sort -rn | head
9124 hash session:...
37 string session:...
A minority type in a namespace pinpoints the offending writer.
Step 4: Inspect recent commands live
# WARNING: MONITOR is expensive; use briefly on a replica or low-traffic node
redis-cli MONITOR | grep -iE 'session:42'
You will see the command that wrote the wrong type.
Example Root Cause Analysis
After deploying a new session store, the app began throwing WRONGTYPE on HGETALL session:<id> for a fraction of users. TYPE session:42 returned string, not hash.
redis-cli --scan --pattern 'session:*' | while read k; do redis-cli TYPE "$k"; done \
| sort | uniq -c
9124 hash
37 string
The old code path stored sessions as a serialized JSON string (SET session:<id> <json>); the new code reads them as a hash (HGETALL). Sessions written by the old build before the deploy remained strings and broke the new reader.
Fixes: (1) add a migration that converts or expires the legacy string sessions, and (2) make the reader defensive — check TYPE (or catch WRONGTYPE) and fall back to re-creating the session. As a stopgap, the legacy keys were expired:
redis-cli --scan --pattern 'session:*' | while read k; do
[ "$(redis-cli TYPE "$k")" = string ] && redis-cli DEL "$k"
done
New logins re-created sessions as hashes and the errors stopped.
Prevention Best Practices
- Namespace keys per type and per feature so two writers can never collide (e.g.
session:hash:<id>). - Treat a data-format change (string ↔ hash) as a migration: version the key prefix or run a backfill.
- Make readers defensive: check
TYPEor catchWRONGTYPEand handle gracefully rather than crashing. - Add integration tests that write and read each key through its real code path.
- Use
--scan(neverKEYS) to audit key types in a namespace during incidents. - Browse more Redis error guides for related data-model pitfalls.
Quick Command Reference
# What type is this key really?
redis-cli TYPE <key>
redis-cli OBJECT ENCODING <key>
redis-cli TTL <key>
# Audit a namespace for mixed types (non-blocking)
redis-cli --scan --pattern 'session:*' | while read k; do
printf '%s %s\n' "$(redis-cli TYPE "$k")" "$k"; done | sort | uniq -c
# Watch the command that writes a key (use sparingly)
redis-cli MONITOR | grep 'session:42'
# Remove offending legacy keys
redis-cli --scan --pattern 'session:*' | while read k; do
[ "$(redis-cli TYPE "$k")" = string ] && redis-cli DEL "$k"; done
Conclusion
WRONGTYPE Operation against a key holding the wrong kind of value means the command and the key’s stored type disagree. It is a deterministic application-level bug, not a broker failure. The usual causes:
- Two code paths use the same key name for different types (collision).
- The wrong command family was issued for the key’s type.
- A serialization/format change left old keys in the previous type.
- TTL/eviction masked the bug into looking intermittent.
TYPE and OBJECT ENCODING on the failing key, plus a --scan audit of the namespace, immediately reveal the mismatch. Fix it with per-type namespacing, defensive readers, and treating format changes as migrations.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.