Definición
Los códigos de estado 5xx de Error del Servidor indican que el servidor encontró un error o es incapaz de cumplir una solicitud válida. A diferencia de los errores 4xx, los errores 5xx son culpa del servidor, no del cliente.
Los códigos de estado 5xx más comunes son:
- 500 Internal Server Error - Error genérico del servidor (excepción no manejada, crash)
- 502 Bad Gateway - Servidor upstream devolvió respuesta inválida (problema de proxy/gateway)
- 503 Service Unavailable - Servidor temporalmente no disponible (mantenimiento, sobrecarga)
- 504 Gateway Timeout - Servidor upstream no respondió a tiempo
- 501 Not Implemented - El servidor no soporta el método solicitado
- 505 HTTP Version Not Supported - El servidor no soporta la versión HTTP
Los códigos 5xx están definidos en RFC 7231 e indican que el cliente debe reintentar la solicitud más tarde (a menudo con backoff exponencial).
Ejemplo
500 Internal Server Error - Excepción No Manejada:
GET /api/users/123 HTTP/1.1
Host: api.example.com
Authorization: Bearer YOUR_TOKEN
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": "Error Interno del Servidor",
"message": "Ocurrió un error inesperado. Por favor, intenta de nuevo más tarde.",
"requestId": "req-abc-123"
}
502 Bad Gateway - Fallo Upstream:
GET /api/users HTTP/1.1
Host: api.example.com
HTTP/1.1 502 Bad Gateway
Content-Type: application/json
{
"error": "Bad Gateway",
"message": "El servicio upstream devolvió una respuesta inválida",
"service": "user-service"
}
503 Service Unavailable - Modo Mantenimiento:
GET /api/users HTTP/1.1
Host: api.example.com
HTTP/1.1 503 Service Unavailable
Retry-After: 3600
Content-Type: application/json
{
"error": "Servicio No Disponible",
"message": "El servicio está temporalmente no disponible por mantenimiento",
"retryAfter": 3600,
"estimatedRestoration": "2026-01-09T12:00:00Z"
}
504 Gateway Timeout - Timeout Upstream:
GET /api/reports/generate HTTP/1.1
Host: api.example.com
HTTP/1.1 504 Gateway Timeout
Content-Type: application/json
{
"error": "Gateway Timeout",
"message": "El servicio upstream no respondió a tiempo",
"timeout": "30s"
}
Ejemplo de Código
JavaScript (Fetch API):
const fetchUser = async (userId, retries = 3, backoff = 1000) => {
for (let attempt = 0; attempt < retries; attempt++) {
try {
const response = await fetch(`https://api.example.com/users/${userId}`, {
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN'
}
});
// Manejar errores 5xx con lógica de reintento
if (response.status === 500) {
const error = await response.json();
console.error('Error Interno del Servidor:', error);
// Reintentar con backoff exponencial
if (attempt < retries - 1) {
const delay = backoff * Math.pow(2, attempt);
console.log(`Reintentando en ${delay}ms... (intento ${attempt + 1}/${retries})`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw new Error('Error del servidor: ' + error.message);
}
if (response.status === 502) {
console.error('Bad Gateway - fallo del servicio upstream');
// Reintentar
if (attempt < retries - 1) {
await new Promise(resolve => setTimeout(resolve, backoff * Math.pow(2, attempt)));
continue;
}
throw new Error('Servicio upstream no disponible');
}
if (response.status === 503) {
const retryAfter = response.headers.get('Retry-After');
console.error('Servicio No Disponible. Reintentar después de:', retryAfter);
// Esperar la duración de Retry-After
if (retryAfter && attempt < retries - 1) {
const delay = parseInt(retryAfter) * 1000;
console.log(`Esperando ${delay}ms antes de reintentar...`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw new Error('Servicio temporalmente no disponible');
}
if (response.status === 504) {
console.error('Gateway Timeout - servicio upstream muy lento');
// Reintentar
if (attempt < retries - 1) {
await new Promise(resolve => setTimeout(resolve, backoff * Math.pow(2, attempt)));
continue;
}
throw new Error('Timeout de solicitud');
}
// Verificar si la respuesta es exitosa
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
if (attempt === retries - 1) {
console.error('Máximo de reintentos alcanzado:', error);
throw error;
}
console.error(`Intento ${attempt + 1} falló:`, error.message);
}
}
};
// Uso
fetchUser(123)
.then(user => console.log('Usuario:', user))
.catch(error => console.error('Falló después de reintentos:', error));
Python (librería requests):
import requests
import time
def fetch_user(user_id, retries=3, backoff=1):
for attempt in range(retries):
try:
response = requests.get(
f'https://api.example.com/users/{user_id}',
headers={
'Accept': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN'
},
timeout=30
)
# Manejar errores 5xx con lógica de reintento
if response.status_code == 500:
error = response.json()
print(f'Error Interno del Servidor: {error}')
# Reintentar con backoff exponencial
if attempt < retries - 1:
delay = backoff * (2 ** attempt)
print(f'Reintentando en {delay}s... (intento {attempt + 1}/{retries})')
time.sleep(delay)
continue
raise Exception(f"Error del servidor: {error.get('message')}")
if response.status_code == 502:
print('Bad Gateway - fallo del servicio upstream')
# Reintentar
if attempt < retries - 1:
time.sleep(backoff * (2 ** attempt))
continue
raise Exception('Servicio upstream no disponible')
if response.status_code == 503:
retry_after = response.headers.get('Retry-After')
print(f'Servicio No Disponible. Reintentar después de: {retry_after}')
# Esperar la duración de Retry-After
if retry_after and attempt < retries - 1:
delay = int(retry_after)
print(f'Esperando {delay}s antes de reintentar...')
time.sleep(delay)
continue
raise Exception('Servicio temporalmente no disponible')
if response.status_code == 504:
print('Gateway Timeout - servicio upstream muy lento')
# Reintentar
if attempt < retries - 1:
time.sleep(backoff * (2 ** attempt))
continue
raise Exception('Timeout de solicitud')
# Verificar si la respuesta es exitosa
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
if attempt == retries - 1:
print(f'Máximo de reintentos alcanzado: {e}')
raise
print(f'Intento {attempt + 1} falló: {e}')
# Uso
try:
user = fetch_user(123)
print(f'Usuario: {user}')
except Exception as error:
print(f'Falló después de reintentos: {error}')
Diagrama
graph TB
subgraph "Errores 5xx del Servidor"
E500[500 Internal Error
Excepción no manejada]
E502[502 Bad Gateway
Upstream inválido]
E503[503 Unavailable
Mantenimiento/sobrecarga]
E504[504 Timeout
Upstream lento]
E501[501 Not Implemented
Método no soportado]
end
subgraph "Acciones del Cliente"
A1[Reintentar con backoff]
A2[Verificar estado upstream]
A3[Esperar Retry-After]
A4[Aumentar timeout]
A5[Usar método diferente]
end
subgraph "Acciones del Servidor"
S1[Corregir bug, desplegar]
S2[Arreglar servicio upstream]
S3[Escalar, finalizar mantenimiento]
S4[Optimizar upstream]
S5[Implementar método]
end
E500 --> A1
E500 --> S1
E502 --> A2
E502 --> S2
E503 --> A3
E503 --> S3
E504 --> A4
E504 --> S4
E501 --> A5
E501 --> S5
Analogía
Piensa en los errores 5xx como problemas en la cocina de un restaurante:
- 500 Internal Server Error → “El horno se rompió, no podemos cocinar tu pedido”
- 502 Bad Gateway → “Nuestro proveedor nos envió ingredientes en mal estado”
- 503 Service Unavailable → “Estamos cerrados por renovaciones, vuelve en una hora”
- 504 Gateway Timeout → “El camión de entrega es muy lento, nos cansamos de esperar”
El problema está con el restaurante (servidor), no con tu pedido (solicitud).
Buenas Prácticas
- No Exponer Stack Traces - Nunca devolver errores internos o stack traces en respuestas 5xx
- Incluir IDs de Solicitud - Agregar IDs únicos de solicitud para debugging y soporte
- Establecer Retry-After - Incluir encabezado
Retry-Aftercon 503 para guiar el timing de reintento - Registrar Todo - Registrar todos los errores 5xx con contexto completo para debugging
- Usar Circuit Breakers - Prevenir fallos en cascada en microservicios
- Implementar Reintentos - Reintentar errores 5xx con backoff exponencial
- Monitorear Tasas 5xx - Alertar sobre tasas elevadas de errores 5xx
- Degradación Elegante - Devolver datos parciales o respuestas en caché cuando sea posible
Errores Comunes
- Exponer Detalles Internos - Incluir stack traces, errores de base de datos o rutas de archivos
- 500 para Todo - Usar 500 para todos los errores en lugar de códigos específicos
- Sin Retry-After - No indicar a los clientes cuándo reintentar durante mantenimiento
- Sin IDs de Solicitud - Hacer imposible rastrear solicitudes fallidas específicas
- Ignorar Errores 5xx - No registrar o monitorear errores del servidor
- Sin Lógica de Reintento - Clientes que no implementan backoff exponencial para fallos transitorios
- Fallos en Cascada - No usar circuit breakers para prevenir fallos downstream