Definición
404 Not Found y 410 Gone son ambos códigos de error del cliente HTTP que indican que un recurso no está disponible, pero transmiten diferentes significados semánticos sobre el estado del recurso.
404 Not Found:
- Significado: El recurso solicitado no pudo encontrarse en el servidor
- Razón: El recurso nunca existió, URI incorrecta, o movido sin redirección
- Permanencia: El estado puede ser temporal o permanente (ambiguo)
- Caché: Los clientes pueden reintentar más tarde (podría ser un problema temporal)
- Caso de Uso: El recurso no existe, URL incorrecta, o elementos eliminados de forma suave
410 Gone:
- Significado: El recurso existió previamente pero ha sido eliminado permanentemente
- Razón: Eliminación permanente intencional (ej. contenido removido, usuario eliminó cuenta)
- Permanencia: Explícitamente permanente (el recurso NUNCA volverá)
- Caché: Los clientes no deben reintentar y pueden purgar referencias en caché
- Caso de Uso: Eliminación de contenido, promociones expiradas, cuentas de usuario eliminadas
Distinción Clave:
- 404 → “No tengo ese recurso” (ambiguo - podría volver)
- 410 → “Lo tenía, pero se fue para siempre” (definitivo)
Ejemplo
404 Not Found - El Recurso Nunca Existió:
GET /api/users/999 HTTP/1.1
Host: api.example.com
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": "No encontrado",
"message": "El usuario con ID 999 no existe"
}
404 Not Found - URL Incorrecta:
GET /api/usres/123 HTTP/1.1
Host: api.example.com
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": "No encontrado",
"message": "El endpoint solicitado no existe. ¿Quisiste decir /api/users/123?"
}
410 Gone - Eliminado Permanentemente:
GET /api/users/123 HTTP/1.1
Host: api.example.com
HTTP/1.1 410 Gone
Content-Type: application/json
{
"error": "Eliminado",
"message": "Esta cuenta de usuario fue eliminada permanentemente el 2026-01-05",
"deletedAt": "2026-01-05T10:30:00Z",
"reason": "El usuario solicitó la eliminación de la cuenta"
}
410 Gone - Contenido Expirado:
GET /api/promotions/summer-sale-2025 HTTP/1.1
Host: api.example.com
HTTP/1.1 410 Gone
Content-Type: application/json
{
"error": "Eliminado",
"message": "Esta promoción ha expirado y ya no está disponible",
"expiredAt": "2025-09-01T00:00:00Z",
"alternative": "/api/promotions/current"
}
Ejemplo de Código
JavaScript (Fetch API):
const fetchUser = async (userId) => {
try {
const response = await fetch(`https://api.example.com/users/${userId}`, {
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN'
}
});
// Manejar 404 Not Found
if (response.status === 404) {
const error = await response.json();
console.warn('404 No encontrado:', error.message);
// Podría reintentar más tarde o verificar si la URL es correcta
// El recurso podría existir en una ubicación diferente
throw new Error(`Usuario ${userId} no encontrado`);
}
// Manejar 410 Gone
if (response.status === 410) {
const error = await response.json();
console.error('410 Eliminado:', error.message);
// Recurso eliminado permanentemente - no reintentar
// Eliminar de caché, borrar marcadores, etc.
removeFromCache(userId);
throw new Error(`Usuario ${userId} fue eliminado permanentemente: ${error.message}`);
}
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error('Error obteniendo usuario:', error);
throw error;
}
};
const removeFromCache = (userId) => {
// Eliminar de caché local
localStorage.removeItem(`user-${userId}`);
// Eliminar de marcadores de UI
console.log(`Usuario ${userId} eliminado de caché`);
};
// Ejemplo: Manejo con diferente feedback de UI
const displayUser = async (userId) => {
try {
const user = await fetchUser(userId);
console.log('Usuario:', user);
} catch (error) {
if (error.message.includes('no encontrado')) {
// 404 - podría ser temporal
alert('Usuario no encontrado. Por favor, verifica el ID del usuario e intenta de nuevo.');
} else if (error.message.includes('eliminado permanentemente')) {
// 410 - permanente, no ofrecer reintento
alert('Esta cuenta de usuario ha sido eliminada permanentemente y no puede accederse.');
window.location.href = '/users'; // Redirigir a lista de usuarios
}
}
};
Python (librería requests):
import requests
def fetch_user(user_id):
try:
response = requests.get(
f'https://api.example.com/users/{user_id}',
headers={
'Accept': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN'
}
)
# Manejar 404 Not Found
if response.status_code == 404:
error = response.json()
print(f'404 No encontrado: {error.get("message")}')
# Podría reintentar más tarde o verificar si la URL es correcta
# El recurso podría existir en una ubicación diferente
raise FileNotFoundError(f'Usuario {user_id} no encontrado')
# Manejar 410 Gone
if response.status_code == 410:
error = response.json()
print(f'410 Eliminado: {error.get("message")}')
# Recurso eliminado permanentemente - no reintentar
# Eliminar de caché, borrar marcadores, etc.
remove_from_cache(user_id)
raise Exception(f'Usuario {user_id} fue eliminado permanentemente: {error.get("message")}')
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f'Error obteniendo usuario: {e}')
raise
def remove_from_cache(user_id):
# Eliminar de caché/base de datos
print(f'Usuario {user_id} eliminado de caché')
# Ejemplo: Manejo con diferente feedback de UI
def display_user(user_id):
try:
user = fetch_user(user_id)
print(f'Usuario: {user}')
except FileNotFoundError as e:
# 404 - podría ser temporal
print(f'Usuario no encontrado: {e}')
print('Por favor, verifica el ID del usuario e intenta de nuevo.')
except Exception as e:
# 410 - permanente, no ofrecer reintento
if 'eliminado permanentemente' in str(e):
print(f'Usuario eliminado permanentemente: {e}')
print('Esta cuenta de usuario no puede accederse.')
Diagrama
flowchart TB
START[GET /api/resource/123] --> EXISTS{¿Recurso
Existe?}
EXISTS -->|No| EVER_EXISTED{¿Alguna vez
Existió?}
EXISTS -->|Sí| RETURN_200[Devolver 200 OK
con datos del recurso]
EVER_EXISTED -->|Nunca| RETURN_404[Devolver 404 Not Found
Recurso desconocido]
EVER_EXISTED -->|Sí, Eliminado| PERMANENT{¿Eliminación
Permanente?}
PERMANENT -->|Sí| RETURN_410[Devolver 410 Gone
Eliminado permanentemente]
PERMANENT -->|No| RETURN_404_SOFT[Devolver 404 Not Found
Eliminado suave/oculto]
RETURN_404 --> CLIENT_404[Cliente: Verificar URL
Puede reintentar más tarde]
RETURN_404_SOFT --> CLIENT_404_SOFT[Cliente: Verificar permisos
Puede reintentar]
RETURN_410 --> CLIENT_410[Cliente: Purgar caché
Nunca reintentar]
RETURN_200 --> CLIENT_200[Cliente: Usar recurso]
style RETURN_404 fill:#ffa726
style RETURN_404_SOFT fill:#ffa726
style RETURN_410 fill:#ef5350
style RETURN_200 fill:#66bb6a
Analogía
Piensa en 404 vs 410 como buscar un libro en una biblioteca:
- 404 Not Found → “No tenemos ese libro” (quizás nunca lo tuvimos, o está prestado, o extraviado)
- 410 Gone → “Solíamos tenerlo, pero lo eliminamos permanentemente de la colección” (descartado, destruido o dado de baja)
Con 404, podrías volver a consultar más tarde. Con 410, no te molestes - nunca volverá.
Buenas Prácticas
- Usar 410 para Eliminaciones Intencionales - Cuando deliberadamente eliminas contenido permanentemente
- Usar 404 para Recursos Desconocidos - Cuando el recurso nunca existió o ubicación desconocida
- Incluir Timestamp de Eliminación - Agregar campo
deletedAten respuestas 410 - Sugerir Alternativas - Proporcionar enlaces a recursos similares en respuestas 410
- Cachear Respuestas 410 - Los clientes pueden cachear 410 para evitar solicitudes repetidas
- Registrar Razones de Eliminación - Rastrear por qué los recursos fueron eliminados permanentemente
- Eliminación Suave vs Dura - Usar 404 para eliminaciones suaves, 410 para eliminaciones duras
Errores Comunes
- Usar 404 para Todo - No usar 410 cuando los recursos son eliminados permanentemente
- Sin Info de Eliminación - No explicar por qué el recurso se fue en respuestas 410
- Semántica Inconsistente - Usar 410 para indisponibilidad temporal (debería ser 503)
- Sin Timestamp - No incluir cuándo fue eliminado el recurso en respuestas 410
- Reintentar 410 - Clientes reintentando respuestas 410 (deberían purgar de caché)
- 404 para Eliminaciones Suaves - Confundir eliminaciones suaves con eliminaciones permanentes
- Sin Encabezados de Caché - No establecer caché apropiada para respuestas 404/410
Estándares y RFCs
Standards & RFCs