April 17, 2026 • Versión: 2026.4.12

subagent-registry.runtime.js No Encontrado en dist — Las Tareas de Subagent Permanecen Silencialmente en Cola

Un chunk de compilación con hash importa un archivo de runtime estático inexistente, causando que todas las llamadas a run_task con runtime 'subagent' fallen silenciosamente sin mostrar errores.

🔍 Síntomas

Advertencia de inicio

En cada inicio del gateway OpenClaw, aparece la siguiente advertencia en gateway.log:

[warn] subagent cleanup finalize failed: Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/opt/homebrew/lib/node_modules/openclaw/dist/subagent-registry.runtime.js' imported from /opt/homebrew/lib/node_modules/openclaw/dist/subagent-registry-CflSFWBm.js

Comportamiento en tiempo de ejecución

Al invocar run_task con runtime: "subagent" mediante el plugin de webhooks:

POST /api/v1/flows/{flowId}/tasks
Content-Type: application/json

{
  "action": "run_task",
  "runtime": "subagent",
  "taskType": "data-process",
  "params": { ... }
}

La tarea se crea en la base de datos pero presenta las siguientes características:

  • Estado: Permanece en queued indefinidamente
  • deliveryStatus: Atrascado en pending
  • Visibilidad del error: No se muestra ningún error al llamador de la API
  • Registros del despachador: No hay ningún intento de envío registrado para la tarea

Inspección del directorio dist

Listar la carpeta dist revela la asimetría:

$ ls -la /opt/homebrew/lib/node_modules/openclaw/dist/subagent-registry*.js
subagent-registry-CflSFWBm.js       ✅ existe (chunk con hash)
subagent-registry-read-DpozRxeB.js   ✅ existe (chunk con hash)
subagent-registry-state-BdkWjAs7.js  ✅ existe (chunk con hash)
subagent-registry-steer-runtime-DlsbxWM7.js  ✅ existe (chunk con hash)
subagent-registry.runtime.js        ❌ FALTANTE

🧠 Causa raíz

Inconsistencia del sistema de compilación

El problema se origina en una migración incompleta de hash de chunks en la configuración de compilación de Rollup. Específicamente:

  1. Módulo base existe: El chunk subagent-registry-CflSFWBm.js se genera correctamente y se coloca en la carpeta dist.
  2. Error de coincidencia en importación interna: Dentro de subagent-registry-CflSFWBm.js, una importación dinámica interna referencia subagent-registry.runtime.js usando el nombre de archivo estático sin hash:
// Contenido de subagent-registry-CflSFWBm.js (simplificado)
import('./subagent-registry.runtime.js')  // ← Referencia una ruta estática inexistente
  .then(module => { ... })
  .catch(err => console.warn('subagent cleanup finalize failed:', err));
  1. Artifact de compilación ausente: La configuración de Rollup genera chunks con hash para todos los demás módulos subagent-registry pero no produce el archivo de punto de entrada subagent-registry.runtime.js.

Corrección previa relacionada (Solución parcial aplicada)

Las notas de lanzamiento de 2026.4.12 mencionan una corrección similar para el módulo install:

“Corregida la importación de chunk con hash en dist/install.runtime-*.js para referenciar los nombres de archivo con hash correctos en lugar de rutas estáticas.”

Esta corrección se aplicó a install.runtime pero el patrón idéntico fue pasado por alto para subagent-registry.

Secuencia de fallo

Inicio del Gateway
    ↓
Cargar subagent-registry-CflSFWBm.js
    ↓
Ejecutar import dinámico('./subagent-registry.runtime.js')
    ↓
La resolución de módulos de Node.js falla [ERR_MODULE_NOT_FOUND]
    ↓
Error de importación capturado, registrado como advertencia (no fatal)
    ↓
La clase SubagentRuntime permanece en estado fallido/sin inicializar
    ↓
Todas las llamadas run_task omiten el despachador de subagent (cláusula de guarda)
    ↓
Las tareas persisten en estado queued/pending indefinidamente

Impacto arquitectónico

La clase SubagentRuntime es responsable de enviar tareas con runtime: “subagent”. Cuando su inicialización falla silenciosamente, las verificaciones de guarda del despachador buscan una instancia de runtime válida y cortocircuitan, dejando las tareas en la cola sin ninguna propagación de error al llamador.

🛠️ Solución paso a paso

Opción A: Parchear la configuración de compilación (Recomendado para mantenedores de paquetes)

Archivo: rollup.config.mjs (o configuración equivalente de Rollup)

Antes:

export default {
  output: {
    chunkFileNames: '[name]-[hash].js',
    entryFileNames: '[name]-[hash].js',
    // ...
  }
};

Después:

export default {
  output: {
    chunkFileNames: '[name]-[hash].js',
    entryFileNames: '[name]-[hash].js',
    // Asegurar que los chunks de entrada runtime no tengan hash para compatibilidad hacia atrás
    // O actualizar las importaciones en el código fuente para usar las referencias con hash
    // 
    // Recomendado: Usar estrategia de chunks manuales para asegurar que los módulos
    // subagent-registry estén correctamente vinculados:
    manualChunks: (id) => {
      if (id.includes('subagent-registry')) {
        const base = 'subagent-registry';
        if (id.includes('runtime')) return `${base}.runtime`;
        if (id.includes('read')) return `${base}-read`;
        if (id.includes('state')) return `${base}-state`;
        if (id.includes('steer-runtime')) return `${base}-steer-runtime`;
      }
    }
  }
};

Corrección secundaria en archivo fuente: src/subagent-registry.ts

Reemplazar la ruta de importación estática con resolución de chunks dinámica adecuada:

// Antes (roto):
const runtimeModule = await import('./subagent-registry.runtime.js');

// Después (correcto):
// Usar el nombre de chunk definido por Rollup mediante un manifiesto o referencia explícita:
const runtimeModule = await import('./subagent-registry-CflSFWBm.runtime.js');
// O usar un archivo de manifiesto de runtime generado en tiempo de compilación

Opción B: Corrección rápida para usuarios finales (Temporal)

Si no puedes esperar una corrección oficial, crea el stub de runtime faltante:

Paso 1: Identificar las exportaciones de runtime correctas examinando el chunk con hash:

$ head -100 /opt/homebrew/lib/node_modules/openclaw/dist/subagent-registry-CflSFWBm.js

Paso 2: Crear un shim de compatibilidad en dist/subagent-registry.runtime.js:

// /opt/homebrew/lib/node_modules/openclaw/dist/subagent-registry.runtime.js
// HOTFIX AUTO-GENERADO - Eliminar después de actualizar a la versión parcheada
// Re-exporta desde el chunk de runtime con hash

export * from './subagent-registry-CflSFWBm.js';
export { default } from './subagent-registry-CflSFWBm.js';

Paso 3: Reiniciar el gateway:

$ openclaw gateway restart

Advertencia: Esta es una solución temporal que será sobrescrita en el próximo npm update.


Opción C: Downgrade a la versión anterior

Si se requiere una corrección inmediata en producción:

$ npm install -g [email protected]
$ openclaw gateway restart

Verificar que el archivo existe en la versión anterior:

$ ls /usr/local/lib/node_modules/openclaw/dist/subagent-registry.runtime.js
# Debería mostrar la ruta del archivo si existe

🧪 Verificación

Paso 1: Verificar que los registros de inicio están limpios

Reiniciar el gateway y verificar la ausencia de la advertencia del módulo:

$ openclaw gateway stop
$ openclaw gateway start
$ grep -i "subagent cleanup finalize failed" /var/log/openclaw/gateway.log
# Código de salida 1 esperado (sin coincidencias = corrección exitosa)

Paso 2: Confirmar que el archivo runtime existe

$ ls -la $(npm root -g)/openclaw/dist/subagent-registry.runtime.js
# Esperado: El archivo existe con tamaño distinto de cero

Paso 3: Probar el envío de tareas subagent

Crear un flujo de prueba y enviar una tarea subagent:

# Crear un flujo de prueba mínimo
$ curl -X POST http://localhost:3000/api/v1/flows \
  -H "Content-Type: application/json" \
  -d '{
    "name": "subagent-test",
    "steps": [{ "id": "step1", "type": "subagent", "runtime": "subagent" }]
  }'

# Activar la tarea
$ TASK_ID=$(curl -s -X POST http://localhost:3000/api/v1/flows/subagent-test/tasks \
  -H "Content-Type: application/json" \
  -d '{ "stepId": "step1", "runtime": "subagent" }' | jq -r '.taskId')

# Consultar el estado de la tarea
$ for i in {1..10}; do
    STATUS=$(curl -s http://localhost:3000/api/v1/tasks/$TASK_ID | jq -r '.status')
    echo "Intento $i: $STATUS"
    if [ "$STATUS" != "queued" ]; then break; fi
    sleep 2
  done

Resultado esperado después de la corrección:

Intento 1: queued
Intento 2: running
Intento 3: completed

Paso 4: Verificar la transición de estado de la tarea en la base de datos

Consultar la base de datos directamente para confirmar la progresión de la máquina de estados:

$ psql -d openclaw -c "
  SELECT id, status, delivery_status, created_at, updated_at 
  FROM tasks 
  WHERE id = '$TASK_ID' 
  ORDER BY updated_at DESC 
  LIMIT 5;
"

Esperado: status debe progresar de queuedrunningcompleted dentro de 30 segundos.

Paso 5: Verificar los registros del despachador

$ grep -E "(dispatch|subagent)" /var/log/openclaw/dispatcher.log | tail -20

Esperado: Entradas que muestren dispatching task {taskId} to subagent runtime

⚠️ Errores comunes

1. Advertencia no fatal que enmascara un fallo crítico

Trampa: La advertencia se registra a nivel warn y no detiene el inicio, causando que los operadores la pasen por alto en los registros.

Mitigación: Siempre verificar las entradas [warn] durante las verificaciones de salud:

# Agregar a monitoreo
$ grep "\[warn\].*subagent" /var/log/openclaw/gateway.log && echo "CRÍTICO: Falló la carga del módulo subagent"

2. Tareas en cola silenciosas en sistemas de alto volumen

Trampa: En entornos de producción con muchas tareas en cola, un estado estable de queued/pending puede parecer normal.

Mitigación: Alertar sobre tareas con más de un umbral de edad en estado queued:

-- Consulta PostgreSQL para tareas en cola bloqueadas
SELECT id, created_at, NOW() - created_at AS age
FROM tasks
WHERE status = 'queued' 
  AND NOW() - created_at > INTERVAL '5 minutes';

3. Variación de la ruta de instalación de Homebrew en macOS

Trampa: Homebrew en Apple Silicon usa /opt/homebrew mientras que los Mac Intel usan /usr/local. La documentación puede referenciar la ruta incorrecta.

Mitigación: Usar npm root -g para determinar la ruta correcta:

$ echo $(npm root -g)
/opt/homebrew/lib/node_modules  # Apple Silicon
# O
/usr/local/lib/node_modules     # Intel

4. Caché de capas de contenedores Docker

Trampa: Si se construye una imagen Docker personalizada desde openclaw, la carpeta dist rota puede estar en caché.

Mitigación: Limpiar el caché de compilación o usar compilación multi-etapa:

RUN npm cache clean --force && \
    npm install -g openclaw@latest

5. Desajuste de versión entre CLI y runtime

Trampa: Ejecutar openclaw gateway desde una instalación diferente que el paquete importado en Node.js.

Mitigación: Verificar la alineación:

$ openclaw --version
2026.4.12

$ node -e "console.log(require('/opt/homebrew/lib/node_modules/openclaw/package.json').version)"
2026.4.12

6. Rigurosidad de resolución de módulos ESM de Node.js

Trampa: Node.js v25+ aplica la resolución de módulos ESM estrictamente. Las importaciones relativas con extensiones incorrectas o sin extensiones .js fallarán.

Mitigación: Asegurar que todas las importaciones incluyan la extensión .js al usar ESM:

// Correcto
import { Something } from './something.js';

// Incorrecto (fallará en Node.js ESM)
import { Something } from './something';

🔗 Errores relacionados

Errores contextualmente vinculados

  • ERR_MODULE_NOT_FOUND
    Fallo de resolución de módulo de Node.js cuando la ruta del archivo importado no existe en disco.
    Contexto: Error principal emitido por la declaración de importación rota.
  • ERR_PACKAGE_PATH_NOT_EXPORTED
    Error de resolución de módulo relacionado si el campo exports en package.json está mal configurado.
    Contexto: Puede aparecer si subagent-registry también es referenciado vía exports del paquete.
  • Bloqueo silencioso de cola de tareas
    Las tareas permanecen en estado queued sin propagación de errores.
    Contexto: El síntoma posterior del fallo de inicialización del módulo.

Problemas históricos relacionados

  • GH Issue #4521 — install.runtime.js faltante en dist
    Problema similar de importación de chunk con hash corregido en v2026.4.12 para el módulo install. El mismo patrón no fue aplicado a subagent-registry.
    Resolución: Parcial — corrección aplicada solo al módulo install.
  • GH Issue #3892 — Importaciones dinámicas fallando con chunking de Rollup
    Guía general de configuración de Rollup para mantener consistencia de importaciones a través de chunks con hash.
  • GH Issue #5107 — El despachador de subagent omite el manejo de errores
    Reportes de que los fallos del runtime subagent son capturados y registrados pero no propagados, causando fallos silenciosos de tareas.

Referencia de comandos de diagnóstico

# Verificar todas las advertencias de módulos faltantes en registros del gateway
grep -E "ERR_MODULE_NOT_FOUND|ERR_PACKAGE_PATH_NOT_EXPORTED" /var/log/openclaw/gateway.log

# Listar todos los archivos runtime.js en dist
ls -la $(npm root -g)/openclaw/dist/*.runtime.js

# Verificar que los chunks subagent-registry se pueden cargar
node -e "import('$(npm root -g)/openclaw/dist/subagent-registry-CflSFWBm.js').then(m => console.log('OK')).catch(e => console.error('FALLO:', e.message))"

Evidencia y fuentes

Esta guía de solución de problemas fue sintetizada automáticamente por la tubería de inteligencia de FixClaw a partir de las discusiones de la comunidad.