Redis: WRONGTYPE Operation against a key holding the wrong kind of value
Cómo resolver el error WRONGTYPE en Redis. Ocurre cuando intentas usar un comando de un tipo de dato sobre una clave que almacena otro tipo diferente.
¿Por qué ocurre?
Redis es estrictamente tipado por clave. El error WRONGTYPE ocurre cuando: - Una clave existe como String pero intentas usar comandos de List, Set, Hash o ZSet sobre ella - La clave fue creada con un tipo y en otra parte del código se usa como otro tipo - Cambio de lógica: antes guardabas un String simple y ahora quieres guardar un Hash - En apps con múltiples servicios, dos servicios usan la misma clave con tipos distintos
Solución paso a paso
1. Verificar el tipo actual de la clave
# En redis-cli
TYPE mi:clave# Respuestas posibles: string, list, set, hash, zset, stream
2. Eliminar la clave y recrearla con el tipo correcto
# Ver el valor actual
GET mi:clave # si es string
HGETALL mi:clave # si es hash
LRANGE mi:clave 0 -1 # si es list# Eliminar y recrear
DEL mi:clave
HSET mi:clave campo1 "valor1" campo2 "valor2"
3. En Node.js con ioredis — manejar el error
import Redis from 'ioredis'
const redis = new Redis()async function guardarUsuario(userId, userData) {
const key = user:${userId}
try {
// Verificar tipo antes de escribir
const tipo = await redis.type(key)
if (tipo !== 'none' && tipo !== 'hash') {
await redis.del(key)
console.warn(Clave ${key} tenía tipo incorrecto (${tipo}), eliminada)
}
await redis.hset(key, userData)
} catch (error) {
if (error.message.includes('WRONGTYPE')) {
await redis.del(key)
await redis.hset(key, userData)
} else {
throw error
}
}
}
4. Convención de naming para evitar colisiones de tipo
// Usar prefijos descriptivos del tipo
const KEYS = {
userHash: (id) => user:hash:${id}, // HSET/HGET
sessionStr: (id) => session:str:${id}, // SET/GET
feedList: (id) => feed:list:${id}, // LPUSH/LRANGE
tagsSet: (id) => tags:set:${id}, // SADD/SMEMBERS
rankZset: () => rank:zset:global, // ZADD/ZRANGE
}// Nunca mezclarás tipos en la misma clave
await redis.hset(KEYS.userHash(userId), { name: 'Fran' })
await redis.set(KEYS.sessionStr(sessionId), token)
5. Migración: cambiar tipo de una clave con datos existentes
async function migrarStringAHash(redis, userId) {
const key = user:${userId}
const tipo = await redis.type(key) if (tipo === 'string') {
// Leer el valor antiguo
const valorAntiguo = await redis.get(key)
const ttl = await redis.ttl(key)
// Borrar y recrear como hash
await redis.del(key)
await redis.hset(key, { legacy_value: valorAntiguo })
// Mantener TTL original
if (ttl > 0) await redis.expire(key, ttl)
}
}
Cómo evitarlo en el futuro
- Define los tipos de todas las claves Redis en un módulo central (`redis/keys.ts`) - Usa prefijos que incluyan el tipo: `user:hash:*`, `session:str:*` - Al cambiar la estructura de datos de una clave, incrementa el namespace: `user:v2:hash:*` - En tests, usa `FLUSHDB` al inicio para limpiar estado residual - Documenta el esquema de Redis igual que documentas el esquema de base de datos
¿Quieres que una IA te ayude? Genera el prompt perfecto para tu error:
Generador de Prompts