KeyError en Python: qué significa y cómo evitarlo
El error que aparece al pedir una clave que no existe en un diccionario. Por qué ocurre, y las tres formas de acceder a diccionarios sin que tu código se rompa.
Python te detiene con algo como esto:
KeyError: 'email'
El mensaje es directo: pediste la clave 'email' de un diccionario, y esa clave no existe ahí. Es uno de los errores más frecuentes al trabajar con diccionarios, datos JSON o formularios. Vamos a entenderlo y, sobre todo, a evitarlo.
Por qué ocurre
Cuando accedes a un diccionario con corchetes y la clave no está, Python no inventa un valor vacío: lanza KeyError.
usuario = {"nombre": "Ana", "edad": 30}
print(usuario["nombre"]) # Ana
print(usuario["email"]) # KeyError: 'email' — esa clave no existe
La causa suele ser una de estas: la clave está mal escrita ("Email" vs "email"), los datos no traían esa clave (muy común con JSON de APIs, donde un campo puede faltar), o asumiste una estructura que no siempre se cumple.
Solución 1: .get() — la más usada
En lugar de corchetes, usa .get(), que devuelve None (o un valor por defecto que tú elijas) cuando la clave no existe, sin lanzar error:
usuario = {"nombre": "Ana"}
email = usuario.get("email") # None, sin error
email = usuario.get("email", "sin correo") # "sin correo" como respaldo
El segundo argumento es el valor por defecto. usuario.get("email", "sin correo") devuelve "sin correo" si la clave falta. Esta es la forma más limpia y la que usarás el 90% de las veces cuando una clave podría no estar.
Solución 2: comprobar con “in”
Si necesitas hacer algo distinto según si la clave existe o no, compruébalo con in:
if "email" in usuario:
enviar_correo(usuario["email"])
else:
print("Este usuario no tiene correo registrado")
El "email" in usuario devuelve True o False según si la clave está. Útil cuando no basta con un valor por defecto, sino que la lógica cambia.
Solución 3: try/except para casos puntuales
Si esperas que la clave casi siempre esté y la ausencia es excepcional, puedes atraparlo:
try:
email = usuario["email"]
except KeyError:
email = "sin correo"
Funciona, pero para el caso común de “dame esto o un respaldo”, .get() es más corto y legible. Reserva el try/except para cuando dentro del bloque pasan varias cosas que podrían fallar.
El caso traicionero: JSON anidado
Donde más muerde el KeyError es con datos JSON de APIs, sobre todo anidados:
datos = respuesta.json()
ciudad = datos["usuario"]["direccion"]["ciudad"] # KeyError si falta cualquier nivel
Si usuario, direccion o ciudad no están, falla. Y con datos externos, nunca tienes garantía de que todos los campos vengan. El acceso seguro encadenando .get():
ciudad = datos.get("usuario", {}).get("direccion", {}).get("ciudad", "desconocida")
El truco: cada .get("clave", {}) devuelve un diccionario vacío si falta, de modo que el siguiente .get() no revienta — simplemente sigue devolviendo vacío hasta el final, donde pones el valor por defecto real. Así, aunque falte cualquier nivel, no hay KeyError.
El diagnóstico
Cuando aparezca KeyError:
- ¿La clave está bien escrita? Revisa mayúsculas y espacios:
"email"≠"Email"≠" email". - ¿Los datos de verdad traen esa clave? Imprime el diccionario (
print(usuario)) y míralo. Con JSON de APIs, no asumas. - Usa
.get()con un valor por defecto para claves que podrían faltar. - Para JSON anidado, encadena
.get("clave", {})en cada nivel.
La regla de fondo: con corchetes accedes cuando estás seguro de que la clave existe; con .get() cuando podría faltar. Elige según la certeza que tengas, y el KeyError deja de aparecer.
¿Te sale al procesar la respuesta de una API concreta y no sabes qué campos llegan? Escríbeme desde contacto y lo revisamos.