Códigos de Estado 5xx de Error del Servidor

Fundamentals Jan 9, 2026 HTTP
http status-codes errors server-errors rest

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

  1. No Exponer Stack Traces - Nunca devolver errores internos o stack traces en respuestas 5xx
  2. Incluir IDs de Solicitud - Agregar IDs únicos de solicitud para debugging y soporte
  3. Establecer Retry-After - Incluir encabezado Retry-After con 503 para guiar el timing de reintento
  4. Registrar Todo - Registrar todos los errores 5xx con contexto completo para debugging
  5. Usar Circuit Breakers - Prevenir fallos en cascada en microservicios
  6. Implementar Reintentos - Reintentar errores 5xx con backoff exponencial
  7. Monitorear Tasas 5xx - Alertar sobre tasas elevadas de errores 5xx
  8. 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

Estándares y RFCs

Términos Relacionados