HTTP 200, pero la consulta falló: cómo detectar errores disfrazados
Una página de mantenimiento puede llegar con 200 OK. Para no convertirla en cero infracciones hay que validar tipo de contenido, estructura y señales de finalización.
Por Marco Ferreiro ·
Una integración solicita resultados y recibe 200 OK. El código parece tranquilizador, pero el cuerpo contiene una portada de mantenimiento, un formulario de ingreso o un mensaje genérico. Si el parser busca una lista y no la encuentra, puede devolver una lista vacía: un error técnico termina publicado como “sin multas”.
HTTP y el negocio hablan en capas. El primero describe la transferencia; el segundo debe demostrar que la consulta terminó con el alcance esperado.
Qué significa realmente 200 OK
RFC 9110 indica que 200 señala que la solicitud tuvo éxito según el método, con una representación cuyo significado depende del contexto. No certifica que una operación interna consultó todas sus fuentes ni que el contenido tenga la forma que el cliente esperaba.
Una aplicación puede responder 200 porque renderizó correctamente su página de error. Un proxy puede sustituir el cuerpo. Un servicio de sesión puede redirigir y acabar en una pantalla de login también exitosa.
Por eso el status es una condición necesaria en algunos flujos, no una prueba suficiente de resultado.
Primera barrera: tipo y framing
El cliente registra status, URL final, Content-Type, tamaño y si la transferencia terminó según el protocolo. RFC 9112 define el framing de HTTP/1.1; una conexión cortada no debería aceptarse como documento completo cuando la longitud o el cierre señalan lo contrario.
Si se esperaba JSON y llega text/html, la respuesta queda fuera del contrato aunque el status sea 200. Si se esperaba HTML, una página de login puede compartir el mismo tipo: habrá que analizar estructura.
No se intenta “arreglar” un JSON incompleto agregando llaves. RFC 8259 define la sintaxis; un parseo fallido es un fallo observable.
Exigir señales positivas
Un detector robusto no depende sólo de una lista de palabras negativas. Define qué debe existir para llamar completa a la respuesta:
- identificador o correlación de la consulta;
- estado terminal explícito;
- fecha de actualización;
- fuentes o cobertura solicitada;
- resultado por fuente, incluso cuando sea vacío;
- versión o estructura reconocida.
Si falta una señal crítica, el estado es indeterminado o fallido. Nunca se fabrica 0 por ausencia de nodos.
Las reglas se versionan por portal. Un rediseño puede cambiar selectores sin que la fuente esté caída.
Señales negativas como segunda capa
Mensajes oficiales de mantenimiento, sesión vencida, acceso denegado o servicio temporalmente no disponible ayudan a clasificar. También una redirección inesperada, un título genérico, un desafío anti-bot o un formulario de autenticación.
No conviene buscar únicamente “error”: una ayuda puede decir “si ves un error” dentro de una página válida. Se comparan estructura, contexto y, cuando es permitido, una huella de plantillas conocidas.
El cuerpo potencialmente sensible no se envía a analytics. Para auditoría se guardan categorías y hashes de fixtures, no respuestas de usuarios.
El falso vacío
El patrón peligroso suele verse así: el selector de filas devuelve cero, por lo tanto el adaptador retorna []. Esa lógica confunde “lista localizada y vacía” con “lista no localizada”.
La implementación debería tener estados separados:
- contenedor encontrado con marcador oficial de cero resultados;
- contenedor encontrado con una o más actas;
- contenedor ausente;
- página no reconocida;
- respuesta incompleta.
Sólo el primer estado puede aportar un cero, y aun así debe conservar qué fuente respondió y cuándo.
Errores dentro de JSON
Una API también puede devolver {"success": false, "message": "mantenimiento"} con status 200. El JSON es válido, pero el resultado no lo es. Otro caso es un objeto con results: [] y sources_pending: 3: publicar cero ocultaría trabajo pendiente.
El schema puede usar variantes explícitas para éxito y error, pero el consumidor debe comprobar el discriminador. Un objeto que coincide con ambos por schemas demasiado abiertos merece corrección del contrato.
Las invariantes de negocio completan la validación: completed no puede coexistir con fuentes pendientes sin una definición documentada.
Fixtures sin atacar portales
No necesitamos provocar mantenimientos reales. Creamos fixtures sintéticos basados en patrones generales: HTML válido de mantenimiento con 200, login después de redirección, JSON de error, JSON parcial y respuesta truncada.
Luego ejecutamos el detector y esperamos que ninguno produzca cero. Un fixture positivo con lista vacía y cobertura completa debe ser el único vacío aceptado. También mutamos títulos y orden de elementos para no sobreajustar a una palabra.
Si un portal publica naturalmente un error durante operación normal y sus términos permiten observarlo, se puede documentar la estructura sin enviar consultas adicionales ni almacenar tokens.
Revisión manual y cuarentena
Cuando una respuesta antes conocida deja de coincidir, se coloca en cuarentena. El sistema informa que la fuente no pudo verificarse y avisa al equipo; no adopta el nuevo HTML como válido automáticamente.
La revisión confirma dominio oficial, contenido, cambios de flujo y campos. Después se actualizan reglas y fixtures con una nueva versión. Las respuestas anteriores conservan la versión con que fueron clasificadas.
Este mecanismo privilegia evitar falsos “sin multas”, aunque ocasionalmente produzca un estado pendiente hasta revisar.
Métricas útiles
Medimos porcentaje de respuestas por categoría, cambios de plantilla, redirecciones, latencia y cantidad de cuarentenas. No enviamos patente, consulta ni cuerpo completo a PostHog o logs generales.
Una suba de 200_no_reconocido puede indicar mantenimiento, WAF o rediseño. Separarla de 5xx hace visible un fallo que los monitores basados sólo en status declararían saludable.
La alerta debe incluir fuente y versión del detector, no datos del usuario.
La frase pública correcta
Si la fuente entregó un error con 200, la respuesta es “no fue posible verificar esta fuente”. Si otras terminaron, el resultado puede ser parcial. Sólo cuando las fuentes previstas completan y declaran ausencia corresponde decir que no informaron infracciones.
El código HTTP sigue siendo valioso, pero no sustituye un contrato. La diferencia entre lista vacía y página equivocada es la diferencia entre información honesta y un cero inventado.
Metodología
- Alcance
- Clasificación de respuestas públicas o fixtures permitidos que usan estado 200 aunque no contengan un resultado funcional completo.
- Unidad de análisis
- Una respuesta sintética con status, headers, longitud, estructura y señales positivas o negativas, procesada por una versión identificada del detector.
- Cobertura
- Semántica HTTP, framing y JSON establecidos por RFC, con ejemplos enteramente sintéticos y sin forzar fallos en portales oficiales.
Limitaciones
- Cada portal requiere reglas versionadas y revisión manual ante cambios de estructura.
- El detector reduce falsos ceros, pero no puede probar cobertura que la fuente no declara.
Fuentes
- RFC 9110 — HTTP Semantics — RFC Editor (consultada el )
- RFC 9112 — HTTP/1.1 — RFC Editor (consultada el )
- RFC 8259 — The JavaScript Object Notation Data Interchange Format — RFC Editor (consultada el )
- Consulta de infracciones — Gobierno de la Ciudad Autónoma de Buenos Aires (consultada el )
Preguntas frecuentes
¿Por qué un servidor devuelve 200 para una página de error?
Puede ser una decisión o defecto de la aplicación, una plantilla de proxy o un flujo que representa el error dentro del cuerpo. HTTP no obliga al cliente a interpretar cualquier 200 como éxito de negocio.
¿Buscar la palabra “error” alcanza?
No. Puede haber falsos positivos y mensajes nuevos. Es más seguro exigir señales positivas versionadas —schema, ID, estado y cobertura— y usar textos conocidos sólo como apoyo.
¿Un JSON válido garantiza una consulta válida?
No. Puede ser un objeto de error o estar truncado semánticamente. Además de parsear JSON hay que validar contrato e invariantes de negocio.
Notas relacionadas
Qué campos demuestran que un portal terminó de responder
Una pantalla vacía puede ser un resultado, un paso intermedio o una carga truncada. Estado final, alcance, paginación, totales y hora de consulta permiten distinguir una respuesta completa de una apariencia de éxito.
Timeout no significa “sin multas”: cómo informar resultados parciales en una integración
Cuando una fuente no responde, el resultado es parcial o indeterminado, nunca cero. Un contrato explícito permite reintentar, alertar y decidir sin producir falsos negativos.
Cobertura de una API: cómo comunicar fuentes caídas y resultados parciales
Una integración de infracciones necesita informar qué fuentes respondió, cuáles fallaron y si el resultado es completo. Un cero sin cobertura comprobada puede inducir decisiones incorrectas.