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
queuedindefinidamente - 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:
- Módulo base existe: El chunk
subagent-registry-CflSFWBm.jsse genera correctamente y se coloca en la carpeta dist. - Error de coincidencia en importación interna: Dentro de
subagent-registry-CflSFWBm.js, una importación dinámica interna referenciasubagent-registry.runtime.jsusando 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));
- 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-*.jspara 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 queued → running → completed 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 campoexportsenpackage.jsonestá 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 estadoqueuedsin 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))"