Resolver

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:

  1. ¿La clave está bien escrita? Revisa mayúsculas y espacios: "email" ≠ "Email" ≠ " email".
  2. ¿Los datos de verdad traen esa clave? Imprime el diccionario (print(usuario)) y míralo. Con JSON de APIs, no asumas.
  3. Usa .get() con un valor por defecto para claves que podrían faltar.
  4. 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.

← Más de Resolver