April 17, 2026 • バージョン: 2026.4.12

subagent-registry.runtime.js の dist からの欠落 — Subagentタスクがサイレントにキューに残り続ける

ハッシュ化されたビルドチャンクが存在しない静的ランタイムファイルをインポートし、runtime 'subagent'を持つすべてのrun_task呼び出しが、エラーを表面化させることなくサイレントに失敗します。

🔍 症状

起動時の警告

OpenClawゲートウェイを起動するたびに、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

ランタイム動作

webhooksプラグイン経由でrun_taskruntime: "subagent"で呼び出すと:

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

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

タスクはデータベースに作成されますが、以下の特徴を示します:

  • 状態: 無期限にqueuedのまま
  • deliveryStatus: pendingで停止
  • エラーの可視性: API呼び出し元にエラーが表面化しない
  • ディスパッチャログ: タスクのディスパッチ試行がログに記録されない

distディレクトリの内容確認

distフォルダを一覧表示すると、不整合が明らかになります:

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

🧠 原因

ビルドシステムの不整合

この問題は、Rollupビルド設定における不完全なチャンクハッシュ移行に起因します。具体的には:

  1. 基本モジュールは存在: チャンクsubagent-registry-CflSFWBm.jsは正しく生成され、distフォルダに配置されています。
  2. 内部インポートの不一致: subagent-registry-CflSFWBm.js内部で、静的なハッシュなしファイル名を使用してsubagent-registry.runtime.jsを参照する内部動的インポートがあります:
// Contents of subagent-registry-CflSFWBm.js (simplified)
import('./subagent-registry.runtime.js')  // ← References non-existent static path
  .then(module => { ... })
  .catch(err => console.warn('subagent cleanup finalize failed:', err));
  1. ビルド成果物の欠落: Rollup設定は他のすべてのsubagent-registryモジュールのハッシュ付きチャンクを生成しますが、subagent-registry.runtime.jsエントリポイントファイルの生成に失敗しています。

関連する以前の問題の修正(部分的な解決策が適用済み)

2026.4.12のリリースノートには、installモジュールに関する同様の修正が記載されています:

“dist/install.runtime-*.jsのハッシュ付きチャンクインポートを修正し、静的パスの代わりに正しいハッシュ付きファイル名を参照するようにしました。”

この修正はinstall.runtimeに適用されましたが、同一のパターンがsubagent-registryで見落とされていました。

障害シーケンス

ゲートウェイ起動
    ↓
subagent-registry-CflSFWBm.jsの読み込み
    ↓
動的import('./subagent-registry.runtime.js')を実行
    ↓
Node.jsモジュール解決が失敗 [ERR_MODULE_NOT_FOUND]
    ↓
インポートエラーがキャッチされ、警告としてログ出力(非致命)
    ↓
SubagentRuntimeクラスがfailed/uninitialized状態のまま
    ↓
すべてのrun_task呼び出しがサブエージェントディスパッチャをバイパス(ガード節)
    ↓
タスクが無期限にqueued/pending状態で存続

アーキテクチャ上の影響

SubagentRuntimeクラスは、runtime: “subagent”を持つタスクのディスパッチを担当しています。初期化が警告のみで失敗した場合、ディスパッチャのガードチェックは有効なランタイムインスタンスを確認し、短絡化して、タスクをエラー伝達なしにキューに残します。

🛠️ 解決手順

オプションA: ビルド設定を修正(パッケージメンテナー向け推奨)

ファイル: rollup.config.mjs(または同等のRollup設定)

修正前:

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

修正後:

export default {
  output: {
    chunkFileNames: '[name]-[hash].js',
    entryFileNames: '[name]-[hash].js',
    // Ensure runtime entry chunks are not hashed for backward compatibility
    // OR update the source imports to use the hashed references
    // 
    // Recommended: Use manual chunk strategy to ensure subagent-registry
    // modules are properly linked:
    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`;
      }
    }
  }
};

ソースファイルの副次的修正: src/subagent-registry.ts

静的なインポートパスを適切な動的チャンク解決に置き換えます:

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

// After (correct):
// Use the Rollup-defined chunk name via a manifest or explicit reference:
const runtimeModule = await import('./subagent-registry-CflSFWBm.runtime.js');
// OR use a runtime manifest file generated at build time

オプションB: ホットフィックス(エンドユーザー向け一時的な解決策)

公式のパッチを待つられない場合、欠落しているランタイムスタブを作成します:

ステップ1: ハッシュ付きチャンクを調べて、正しいランタイムエクスポートを特定します:

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

ステップ2: dist/subagent-registry.runtime.jsに互換性シムを作成します:

// /opt/homebrew/lib/node_modules/openclaw/dist/subagent-registry.runtime.js
// AUTO-GENERATED HOTFIX - Remove after upgrading to patched version
// Re-exports from the hashed runtime chunk

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

ステップ3: ゲートウェイを再起動します:

$ openclaw gateway restart

警告: これは次のnpm updateで上書きされる一時的な回避策です。


オプションC: 以前バージョンへのダウングレード

本番環境で即時の修正が必要な場合:

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

以前バージョンでファイルが存在することを確認します:

$ ls /usr/local/lib/node_modules/openclaw/dist/subagent-registry.runtime.js
# Should output the file path if it exists

🧪 検証

ステップ1: 起動ログがクリーンであることを確認

ゲートウェイを再起動し、モジュールの警告が存在しないことを確認します:

$ openclaw gateway stop
$ openclaw gateway start
$ grep -i "subagent cleanup finalize failed" /var/log/openclaw/gateway.log
# Exit code 1 expected (no matches = fix successful)

ステップ2: ランタイムファイルが存在することを確認

$ ls -la $(npm root -g)/openclaw/dist/subagent-registry.runtime.js
# Expected: File exists with non-zero size

ステップ3: サブエージェントタスクのディスパッチをテスト

テストフローを作成し、サブエージェントタスクをディスパッチします:

# Create a minimal test flow
$ 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" }]
  }'

# Trigger the task
$ 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')

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

修正後の期待される結果:

Attempt 1: queued
Attempt 2: running
Attempt 3: completed

ステップ4: データベースのタスク状態遷移を確認

データベースを直接クエリして、状態機械の進行を確認します:

$ 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;
"

期待される結果: statusは30秒以内にqueuedrunningcompletedと進行するはずです。

ステップ5: ディスパッチャログの確認

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

期待される結果: dispatching task {taskId} to subagent runtimeを示すエントリ

⚠️ よくある落とし穴

1. 致命的障害を隠す致命的でない警告

落とし穴: 警告はwarnレベルでログ出力され、起動を停止しないため、オペレーターがログでこの警告を見落とす可能性があります。

対策: ヘルスチェック時に[warn]エントリを必ず確認します:

# Add to monitoring
$ grep "\[warn\].*subagent" /var/log/openclaw/gateway.log && echo "CRITICAL: Subagent module load failed"

2. 高負荷システムでの静かなタスクキュー詰まり

落とし穴: 多くのキュー済みタスクがある本番環境では、queued/pendingの一定状態が正常にに見える場合があります。

対策: queued状態の閾値を超えたタスクに対してアラートを出します:

-- PostgreSQL query for stale queued tasks
SELECT id, created_at, NOW() - created_at AS age
FROM tasks
WHERE status = 'queued' 
  AND NOW() - created_at > INTERVAL '5 minutes';

3. macOS Homebrewインストールパスの違い

落とし穴: Apple Silicon上のHomebrewは/opt/homebrewを使用し、Intel Macは/usr/localを使用します。ドキュメントが誤ったパスを参照している可能性があります。

対策: npm root -gを使用して正しいパスを判定します:

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

4. Dockerコンテナレイヤーのキャッシュ

落とし穴: openclawからカスタムDockerイメージをビルドする場合、壊れたdistフォルダがキャッシュされる可能性があります。

対策: ビルドキャッシュをクリアするか、マルチステージビルドを使用します:

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

5. CLIとランタイムのバージョン不一致

落とし穴: Node.jsでインポートされたパッケージとは異なるインストールからopenclaw gatewayを実行している可能性があります。

対策: 整合性を確認します:

$ openclaw --version
2026.4.12

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

6. Node.js ESMモジュールの解決の厳格さ

対策: Node.js v25+はESMモジュールの解決を厳格に強制します。誤った拡張子や.js拡張子の欠落がある相対インポートは失敗します。

対策: ESM使用時にすべてのインポートに.js拡張子が含まれていることを確認します:

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

// Incorrect (will fail in Node.js ESM)
import { Something } from './something';

🔗 関連するエラー

文脈的に関連するエラー

  • ERR_MODULE_NOT_FOUND
    インポートされたファイルパスがディスク上に存在しない場合のNode.jsモジュールの解決失敗。
    コンテキスト: 壊れたインポート文から出される主要なエラー。
  • ERR_PACKAGE_PATH_NOT_EXPORTED
    package.jsonexportsフィールドが誤って設定されている場合の関連するモジュールの解決エラー。
    コンテキスト: subagent-registryがパッケージエクスポート経由でも参照されている場合に表示される可能性があります。
  • 静かなタスクキュー詰まり
    タスクがqueued状態でエラーが伝播されないまま存続。
    コンテキスト: モジュールの初期化失敗の下游の現象。

歴史的な関連する問題

  • GH Issue #4521 — install.runtime.jsがdistから欠落
    installモジュールに対するv2026.4.12で修正された同様のハッシュ付きチャンクインポート問題。同じパターンがsubagent-registryに適用されませんでした。
    解決: 部分的な修正 — installモジュールのみに修正を適用。
  • GH Issue #3892 — Rollupチャンキングで動的インポートが失敗
    ハッシュ付きチャンク全体でインポートの一貫性を維持するための一般的なRollup設定ガイダンス。
  • GH Issue #5107 — サブエージェントディスパッチャがエラー処理をバイパス
    サブエージェントランタイムの失敗がキャッチされログ出力されるが伝播されないため、静かなタスク失敗が発生するという報告。

診断コマンドの参照

# Check for all missing module warnings in gateway logs
grep -E "ERR_MODULE_NOT_FOUND|ERR_PACKAGE_PATH_NOT_EXPORTED" /var/log/openclaw/gateway.log

# List all runtime.js files in dist
ls -la $(npm root -g)/openclaw/dist/*.runtime.js

# Verify subagent-registry chunks are loadable
node -e "import('$(npm root -g)/openclaw/dist/subagent-registry-CflSFWBm.js').then(m => console.log('OK')).catch(e => console.error('FAIL:', e.message))"

エビデンスとソース

このトラブルシューティングガイドは、FixClaw Intelligence パイプラインによってコミュニティの議論から自動的に合成されました。