2 · Datos y ERP·4 min de lectura

Un error escrito con cara de dato

6 sep 2026Datos y ERPMétodoAutomatización

El sistema no dejó de funcionar. Siguió funcionando y diciendo que todo iba bien.

Un flujo de n8n recogía mensajes de WhatsApp de la operación —fotos de producción, remisiones, reportes de turno— y un modelo de Groq los leía para decidir qué era cada uno y si alguien debía enterarse. En julio procesó 803 de 859. En agosto, 209 de 895. En septiembre, cero de 226.

Nadie lo notó, y la razón es la peor de todas: el proceso terminaba en «éxito».

Lo que había en el campo del análisis#

Al abrir el último registro que sí traía algo, el campo destinado a la interpretación decía esto:

json
{
  "interpretacion": "Error procesando respuesta AI",
  "raw": "{\"error\":{\"message\":\"The model ... does not exist
          or you do not have access to it.\"}}",
  "urgencia": "baja",
  "notificar": false
}

El sistema había guardado el mensaje de su propia muerte en el campo donde debía ir el análisis. Y como el registro existía y tenía la forma correcta, todo lo que miraba río abajo lo daba por bueno. Peor: se clasificó a sí mismo como urgencia baja y no notificar.

Un error que se detiene y grita se arregla en cinco minutos. Un error que se escribe con cara de dato sobrevive meses.

Tres fallas apiladas, no una#

Cuando por fin lo abrimos, no había una causa. Había tres, y las tres eran ciertas al mismo tiempo. Por eso ninguna revisión superficial las había encontrado.

La primera: un enrutador sin salida por omisión. Los mensajes se repartían en nueve categorías —cotización, producción, cobro, inventario…— y lo que no caía en ninguna simplemente no seguía a ningún lado. La ejecución terminaba, sin error, sin análisis. Lo que no encajaba era el 52% del total: las imágenes. Existía una rama para «otros» y solo la alcanzaba una categoría marginal.

La segunda: una variable de entorno prohibida. El clasificador leía una credencial del entorno del proceso. La plataforma bloquea ese acceso por defecto, así que devolvía «acceso denegado». Y al intentar envolver ese error para reportarlo, el motor tronaba con un mensaje que no tenía nada que ver — de modo que la ejecución entera moría antes de escribir el resultado, incluso cuando el mensaje sí había sido clasificado bien.

La tercera: el modelo dejó de existir. El proveedor retiró la familia de modelos que usábamos. Cada llamada volvía con «el modelo no existe o no tienes acceso». Ese fue el texto que terminó guardado como análisis.

Lo que costó de verdad#

El daño no fue perder 1,751 mensajes sin clasificar, aunque eso ya duele. Fue que cuatro cosas distintas dependían de ese modelo retirado y ninguna avisó: el clasificador, el asistente operativo, un generador de reportes, y el extractor de pedidos que convierte un mensaje de WhatsApp en una cotización. Ese último llevaba semanas devolviendo vacío cada vez que alguien pedía una cotización por chat.

Cuatro funciones muertas por la misma línea, en cuatro archivos distintos, y ninguna con una alarma propia.

Un sistema que reporta «éxito» mientras no produce nada es peor que uno caído. Al caído le crees lo justo; al que dice que va bien le crees todo.

Cómo se destapó#

No fue una alerta. Fue una pregunta ociosa —«¿qué hay acumulado en esas capturas?»— y una consulta que contó cuántos registros tenían análisis por mes. La caída de 803 a 209 a cero se veía en tres renglones.

La herramienta que sí sirvió después fue la que expone la ejecución nodo por nodo: ahí se ve que el enrutador entregó cero elementos en la corrida marcada como exitosa, y el error exacto en la fallida. Sin ese detalle, «éxito» tapa todo.

Las reglas que quedaron#

Un enrutador siempre lleva salida por omisión. Lo que no encaja tiene que ir a algún lado y quedar contado. Si no cabe en ninguna categoría, esa es información, no basura.

Ningún error se guarda en el campo del resultado. Si el análisis falló, el campo del análisis va vacío y el estado dice que falló. Un texto de error en el lugar del dato contamina todo lo que lea después.

Y lo que declara éxito tiene que declarar también qué produjo. «Corrió sin fallar» no es un resultado. El resultado es cuántas filas escribió — y si escribió cero, eso se muestra, no se calla.

Qué hicimos#

Salida por omisión en el enrutador. La llave por credencial de n8n, no por variable de entorno — n8n bloquea el acceso a env en nodos de código y eso mataba la ejecución entera. Y el modelo migrado a uno vigente, probado con una llamada real antes de confiarle nada: de tres candidatos, dos devolvían algo que no era JSON utilizable.

Construimos el detector que faltaba: uno que compara capturas recibidas contra capturas analizadas y avisa cuando la brecha crece. Con él, esto se veía el segundo día. Sin él, tardó treinta y cinco.


Caso real de un canal de captura operativa. Los datos, nombres y volúmenes de cliente se omitieron; el detalle técnico se conserva porque es el que sirve.