Redis · beginner

Redis WRONGTYPE: find the key contract violation

WRONGTYPE means a Redis command was issued against a key whose stored data type does not match the command's expected type. The fix is to identify the key, confirm its actual stored type, and resolve the contract mismatch by aligning the operation, the namespace, or the application code with the canonical type.

The symptoms

  • Server returns the literal error: WRONGTYPE Operation against a key holding the wrong kind of value.
  • The same key works for some commands (for example, simple GET) but fails for others (for example, HGET, LPUSH, SADD).
  • Failures appear after a deploy, refactor, or data migration that changed how the key is written.
  • Different application instances or replicas see the error at different rates, depending on which code path touched the key first.
  • The error does not retry successfully, because the persisted value is consistently a different type.

Likely causes

  • Key namespace collision: two code paths share the same key string but treat it as different types (for example, a plain string vs. a hash).
  • Serializer change: a refactor switched the encoded format, so a key previously written as a string is now read as a hash, list, or set.
  • Legacy data from a migration: older values live under a key as one type, while new code expects a different type.
  • Lua script or MULTI/EXEC pipeline containing a sub-command whose type assumption no longer holds for the key.
  • Manual or out-of-band SET against a key that the application otherwise maintains as a non-string type.
  • Racy writers: a fast writer and a slow reader disagree about the canonical type of the same shared key.

First ten minutes

  1. 01Capture the exact failing key string and the logical database index from the application error or client log.
  2. 02Run TYPE against the key to read the actual stored type and confirm the error reproduces.
  3. 03Identify the code path that issued the failing command and record what type it expected.
  4. 04Search the codebase for every other command issued against the same key to map the implied contract.
  5. 05Scan the keyspace with a prefix-matching pattern to see whether sibling keys are already the same type or the wrong type.
  6. 06Check the recent deploy timeline and any data migration job that touched the key around the first failure.

Evidence to collect

  • The full key name, the logical database index, and the exact error string returned to the client.
  • Server-side timestamp and client address of the rejected command, from the Redis log or MONITOR capture.
  • The application's expected type for the key, taken from the source code or the client wrapper.
  • Recent commits, configuration changes, or migration scripts that altered serialization or key naming.
  • Output of TYPE for the key and any sibling keys discovered with SCAN.
  • Whether the key has a TTL set, since TTL behavior can mask or reveal the contract (strings with TTL vs. non-strings).

Where to look

  • Application logs immediately around the first occurrence of the WRONGTYPE message.
  • The Redis server log for the corresponding timestamp and client source address.
  • Source files that construct the key, including client wrappers, repositories, and Lua scripts.
  • Schema or key-naming documentation, if the project defines canonical key prefixes per type.
  • INFO keyspace output to compare database sizes before and after the incident window.
  • MONITOR or a short, scoped CLI capture window to observe the exact command sequence that triggers the failure.

Diagnostic steps

  1. 01Run TYPE against the failing key and write down the returned type string (string, list, set, hash, zset, stream, or none).
  2. 02Compare the returned type to the command that failed; mismatch between the two is the root cause.
  3. 03Run OBJECT ENCODING to confirm the low-level encoding and rule out surprises such as a list stored as a quicklist.
  4. 04Use SCAN with a prefix pattern to enumerate sibling keys and check whether the wrong type is isolated or widespread.
  5. 05Trace the failing command back to its source file and identify every other call site that touches the same key.
  6. 06If running in a cluster, run CLUSTER KEYSLOT to confirm the key maps to the expected node before assuming the value is local.
  7. 07Compare the current key contract against any documentation or schema file the project maintains for Redis keys.
  8. 08Decide whether the key is incorrectly typed or the application is incorrectly typed, then plan a type-safe fix.

Common mistakes

  • Retrying the same failing command and assuming the error is transient, when the persisted type is stable.
  • Deleting the key immediately to clear the error, without first understanding which writer put the wrong type there.
  • Using KEYS with a wildcard in production to find sibling keys, which blocks the server main thread.
  • Adding a generic try/catch around the failure, hiding the contract violation instead of fixing it.
  • Conflating WRONGTYPE with a connectivity or cluster redirect error, and chasing the wrong system.
  • Refactoring the code to "make the call work" without defining which type is canonical for the key.

Safe fixes

  • Define and document the canonical type for the key in a single client wrapper, and route all reads and writes through it.
  • Introduce distinct key prefixes per data type or per logical entity so different code paths cannot collide on the same key.
  • Add a precondition check in the application that issues a read-only TYPE call once at startup and aborts if the contract is violated.
  • If a migration is intended, drain the old key, switch the writers to the new type, and retire the old code path before resuming traffic.
  • For Lua scripts, validate the type inside the script with a type-checking helper and return a clear error rather than letting WRONGTYPE bubble up.
  • Add a small integration test that exercises the canonical command set against the key and fails the build on any new WRONGTYPE.

Prove the fix

  1. 01The original failing command returns successfully against the same key, with no WRONGTYPE error from the server.
  2. 02TYPE returns the expected type string for the key, and OBJECT ENCODING shows a consistent encoding.
  3. 03A replay of the original request, including any required parameters, produces the same successful response.
  4. 04No new WRONGTYPE messages appear in the application or Redis logs for a sustained observation window.
  5. 05Sibling keys discovered by SCAN all hold the expected type, indicating the contract holds for the namespace.
  6. 06An integration test covering the previously failing path now passes in CI on every run.

Prevention and next steps

  • Centralize key construction in a single client module that enforces a documented type per key prefix.
  • Use distinct prefixes for different data types and different logical entities so collisions are prevented by convention.
  • Add a startup or smoke test that asserts the canonical type of representative keys before the service accepts traffic.
  • Ban ad-hoc manual SET against application-owned keys during incident response, and route any override through a typed helper.
  • Keep a living key contract document that lists name, type, encoding, and TTL for every key the service uses.

Safe commands and checks

redis-cli -n <db> TYPE <key>
redis-cli OBJECT ENCODING <key>
redis-cli -n <db> SCAN 0 MATCH "<prefix>*" COUNT 100
redis-cli INFO keyspace
redis-cli CLUSTER KEYSLOT <key>
redis-cli -n <db> DBSIZE
redis-cli LASTSAVE
Read the Redis server's slowlog and command statistics through the repository's approved read-only observability path; do not use DEBUG commands against an application instance.