Los nodos de código se congelan

Los nodos de código se congelan

Describe el problema/error/pregunta

Mi flujo de trabajo funciona perfectamente, pero cuando adjunto memoria al LLM (OpenAI), que está casi en la mitad del flujo de trabajo, muchos nodos de código que están antes del nodo HTTP (para enviar la carga útil al panel)

Me estoy encontrando con un grave problema de rendimiento donde mis nodos de código se congelan y eventualmente agot el tiempo de espera, pero solo cuando la memoria del LLM está presente en el flujo de trabajo.

Mi flujo de trabajo procesa datos JSON entrantes utilizando algunos nodos de código estándar (realizando limpieza y validación de datos). Más adelante en el flujo de trabajo, tengo un nodo LLM (OpenAI) con un componente de memoria adjunto.

Cuando ejecuto el flujo de trabajo sin la memoria del LLM, todo se ejecuta perfectamente e instantáneamente. Sin embargo, en el momento en que adjunto memoria al LLM, varios nodos de código que se ejecutan antes de un nodo de solicitud HTTP se quedan atrapados en una congelación infinita.

¿Cuál es el mensaje de error (si la hay)?

Algo como esto: ya no hay mensaje de error, solo ejecución infinita. Error:
La ejecución de la tarea agotó el tiempo de espera después de 300 segundos
El ejecutor de tareas tardó demasiado tiempo en esta tarea, por lo que se sospechaba que no respondía y se reinició, y se abortó la tarea. Puedes intentar lo siguiente: 1. Optimiza tu script para evitar tareas de ejecución prolongada, por ejemplo procesando datos en lotes más pequeños. 2. Asegúrate de que todos los caminos en tu script puedan terminar, es decir, sin bucles infinitos. 3. Si tu tarea puede durar razonablemente más de 300 segundos, aumenta el tiempo de espera utilizando la variable de entorno N8N_RUNNERS_TASK_TIMEOUT.

Información sobre tu configuración de n8n

  • Versión de n8n: 2.11.3
  • Base de datos (predeterminado: SQLite): Predeterminado
  • Configuración de n8n EXECUTIONS_PROCESS (predeterminado: own, main): Predeterminado
  • Ejecutando n8n mediante (Docker, npm, n8n cloud, aplicación de escritorio): Docker
  • Sistema operativo: Windows

Hola @sherazbintahir, mientras esperas una respuesta, aquí hay algunas cosas que podrían ayudarte:

Recursos sugeridos

Emparejado automáticamente con tu pregunta.

Documentación:

Foro:

@Fabian_Hagen, @aseefdurrani, @Anshul_Namdev - habéis ayudado con problemas similares antes, ¿podéis echar un vistazo?

Sugerido automáticamente por el bot de comunidad de n8n. Es un piloto - comparte tu opinión aquí.

es una salvaguarda específica de n8n. Significa que el código JavaScript dentro de tus nodos de código se está ejecutando durante más de 300 segundos, lo que hace que n8n Task Runner asuma que está atrapado en un bucle infinito o procesando una tarea imposiblemente grande, por lo que lo mata forzosamente.

Como esto solo ocurre cuando adjuntas Memory al LLM, el componente Memory está cambiando fundamentalmente la estructura de datos, el tamaño o el comportamiento de los datos que fluyen hacia tus nodos de código posteriores.

Cuando Memory está adjunto, el nodo LLM (o la cadena/agente del que forma parte) puede estar pasando el historial de conversación completo o un objeto de estado de memoria grande al flujo de datos principal, en lugar de solo la respuesta final de la IA.

  • El problema: Si tus nodos de código están intentando procesar, limpiar o hacer JSON.stringify() en una entrada que ahora contiene cientos o miles de mensajes históricos, fácilmente superará el tiempo de espera de CPU de 300 segundos.
  • La solución: Necesitas reducir los datos solo a lo que el panel necesita inmediatamente después del nodo LLM.
    • Añade un nodo de código temporal justo después del nodo LLM con este código para ver qué se está pasando realmente:
// Comprueba cuántos elementos hay y el tamaño de los datos
const items = $input.all();
console.log("Total de elementos:", items.length);
console.log("Claves del primer elemento:", Object.keys(items[0].json));
return items;
  • Si ves un masivo array de messages u objeto de memoria, actualiza tus nodos de código posteriores para extraer solo el campo específico que necesitas (p. ej., item.json.message.content o item.json.text) y descarta el resto antes de procesar.

Los objetos Memory en n8n (especialmente cuando se trata de integraciones de LangChain) a veces pueden contener referencias circulares (donde un objeto se refiere a sí mismo).

  • El problema: Si tus nodos de código usan JSON.stringify($input.all()) o pasan todo el objeto de entrada a una función de análisis personalizada, una referencia circular puede causar que el motor JavaScript entre en un bucle infinito intentando serializar el objeto, lo que resulta en el tiempo de espera de 300 segundos.
  • La solución: Nunca hagas stringify de todo $input o $input.all() si contiene salidas de LLM/Memory. Siempre extrae primero los valores de string primitivos:
  // MALO: Puede colgarse si existen referencias circulares
  // const payload = JSON.stringify($input.all()); 

  // BUENO: Extrae solo los datos primitivos que necesitas
  const cleanData = $input.all().map(item => ({
    response: item.json.message?.content || item.json.text,
    // añade otros campos específicos aquí
  }));
  const payload = JSON.stringify(cleanData);

Si tus nodos de código usan bucles while, funciones recursivas o métodos .reduce() que dependen de la estructura del JSON entrante, la adición de Memory podría haber cambiado esa estructura.

  • El problema: Por ejemplo, si tu código tiene un bucle while que procesa un array hasta que esté vacío, pero el componente Memory accidentalmente inyecta un array anidado que sigue regenerándose o no cumple la condición de salida, el bucle se ejecutará indefinidamente.
  • La solución: Revisa todos los bucles while en tus nodos de código. Añade un “contador de seguridad” para forzar su salida si superan un número razonable de iteraciones:
let safetyCounter = 0;
while (myCondition && safetyCounter < 1000) {
    // tu lógica
    safetyCounter++;
}

¿Te ayuda esto?

Como dije, la memoria adjunta con LLM está en el medio del flujo de trabajo.

Y una vez que adjunté la memoria, enfrenté problemas con varios nodos de código, y algunos nodos de código están al inicio del flujo de trabajo (antes de que incluso se ejecute el nodo de memoria llm).

Sin memoria, el flujo de trabajo se completa sin problemas, pero con memoria, el mismo flujo de trabajo comienza a tener problemas en el nodo de código.

Ya que no lo aclaraste claramente, asumo que sucedió después del Agente de IA

Eso es más claro. Eso me suena como una regresión de memoria

¿Ayuda actualizar a la última versión estable de n8n?

Hola @sherazbintahir
Los nodos Code que cuelgan únicamente por la presencia de un subnodo, incluyendo los que se ejecutan antes de este, es el ejecutor de tareas fallando al resolver el tipo de ese subnodo. Cualquier cosa que haga que un nodo Code le pida al proceso principal contexto adicional, una referencia $('Node Name') o $node["Node Name"] o un require() de un módulo externo, envía al ejecutor de nuevo a reconstruir el flujo de trabajo, y un tipo de subnodo que no puede resolver deja esa solicitud sin respuesta hasta que los 300s la maten. Los registros de tu contenedor n8n mostrarán “Unrecognized node type: …” en el momento en que se detiene.
Reescribe esos nodos Code para usar solo $input y $json, y mueve cualquier cosa que necesiten de un nodo anterior a la ruta principal con un nodo Set primero. Desactivar el ejecutor no es una opción en 2.11.3, N8N_RUNNERS_ENABLED está en desuso desde 2.0 y cada ejecución de nodo Code se ejecuta en un ejecutor.

Gracias, será de gran ayuda. Pero estoy confundido aquí porque mi flujo de trabajo completo (120+ nodos) funciona perfectamente sin ningún error, pero cuando adjunto la memoria con LLM (nodo de agente de IA con OpenAI + memoria) enfrento este problema.
Para más información, en el flujo de trabajo sin memoria, utilizo el nodo de OpenAI directamente. Y no estoy enfrentando este problema en todos los nodos de código pero en algunos.

Cuadro Amarillo: Donde estoy adjuntando la memoria con LLM.
Puntos Rojos: Donde estoy enfrentando problemas con los nodos de código. La mayoría de nodos son aquellos en los que estoy construyendo/preparando la carga útil para enviar al panel.

Hola @sherazbintahir

¿Has intentado cambiar a PostgreSQL para descartar el bloqueo de la base de datos SQLite?

services:
  postgres:
    image: postgres:16-alpine
    environment:
      - POSTGRES_USER=n8n_user
      - POSTGRES_PASSWORD=n8n_password
      - POSTGRES_DB=n8n_db
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U n8n_user -d n8n_db"]
      interval: 5s
      timeout: 5s
      retries: 5

  n8n:
    image: n8nio/n8n:2.11.3
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n_db
      - DB_POSTGRESDB_USER=n8n_user
      - DB_POSTGRESDB_PASSWORD=n8n_password
      - EXECUTIONS_PROCESS=own
    depends_on:
      postgres:
        condition: service_healthy

volumes:
  postgres_data:

Hola @sherazbintahir Esto no es lentitud, tus nodos Code están en deadlock, no ocupados.

Desde la v2.0 todos los nodos Code se ejecutan en un proceso task runner separado. Si un script solo usa input/input / input/json, obtiene un payload reducido y se ejecuta al instante. Pero si usa ('NodeName') o ('Node Name') o node['Node Name'], el runner tiene que solicitar todo el flujo de trabajo serializado de vuelta a n8n y reconstruirlo, y eso requiere resolver cada tipo de nodo en el lienzo, incluyendo subnodos. Si adjuntas el subnodo memory y el runner alcanza un tipo que no puede resolver, la solicitud nunca regresa, y tu nodo Code espera eternamente hasta que el watchdog de 300s lo mata. Igual que #20752.

Eso también explica por qué solo algunos de tus nodos Code fallan — los que funcionan son los que nunca acceden fuera de su propio input.

¿Puedes verificar dos cosas?

  1. Ejecútalo con memory adjunto y busca en tus logs:
   docker logs -f <n8n-container> | grep -i "unrecognized node type"
  1. Abre uno de los nodos Code congelados — ¿contiene $('...') o $node[...] en algún lugar?

Si la respuesta es sí a ambas, la solución es rápida: coloca un nodo Set delante de él y pasa el valor como una expresión (={{ $('Clean JSON').first().json.config }} — las expresiones en nodos normales se ejecutan en el proceso principal y no se ven afectadas), luego léelo desde $input dentro del nodo Code. Memory permanece exactamente donde está.

Publica lo que dice la línea del log y te daré la reescritura exacta para tu nodo.

@sherazbintahir La variable no es memoria — es el node swap. Sin memoria utilizaste el nodo OpenAI plano. Para adjuntar memoria tuviste que cambiar al AI Agent, una raíz de clúster LangChain que extrae sub-nodos al lienzo (Chat Model, Memory, tu herramienta search_workwell_memory). El nodo OpenAI se resuelve bien en el ejecutor de tareas; los sub-nodos de Agent a menudo no.

Por qué solo algunos nodos Code: desde la v2.0 todos los nodos Code se ejecutan en un proceso de ejecutor separado.

  • Usa solo $input / $json → carga útil delgada, instantáneo. sí (tus nodos de limpieza/validación)
  • Usa $('Node') / $node['Node'] / $items() — el ejecutor solicita todo el flujo de trabajo serializado y lo reconstruye, lo que significa resolver cada tipo de nodo en tu lienzo de 120 nodos, incluyendo sub-nodos. Un tipo no resoluble — la solicitud nunca vuelve — cuelga hasta que se activa el vigilante de 300s. no (tus constructores de carga útil — los puntos rojos)

Ten en cuenta que el sub-nodo de herramienta también puede causar esto por sí solo: #20752 fue postgrestool, #20132 Apify/Perplexity — allí se colgó incluso aunque el Agent nunca se ejecutara.

Confirma en 30s — deja la memoria adjunta, congela un nodo:

js

// const cfg = $('Prepare Normal Formatter Evidence').first().json;
const cfg = { test: true };

Se ejecuta instantáneamente → confirmado.

Arregla primero lo mejor:

  1. Fusiona el nodo en el nodo Code, luego lee $input.all(). Lo más limpio a tu escala.
  2. Establece el nodo al frente, resuelve valores como expresiones: ={{ $('Parse Extraction').first().json.score }} las expresiones en nodos normales se evalúan en el proceso principal, por lo que son inmunes.
  3. Salta el nodo Code — construye el cuerpo JSON directamente en el nodo HTTP Request con expresiones.

Mantén pairedItem: { item: index } en los elementos devueltos, o las expresiones posteriores reintroducen el problema. La memoria permanece adjunta en los tres.

No ayudará: aumentar N8N_RUNNERS_TASK_TIMEOUT (la espera es ilimitada), o N8N_RUNNERS_ENABLED=false (ignorado en 2.x).

¿Puedes publicar la salida de docker logs -f <n8n-container> | grep -i "unrecognized" mientras ejecutas con el Agent conectado? Eso mostrará si es la memoria o la herramienta.