[Discordスラッシュコマンドが'Done.'を代わりに返す] - Discord Slash Command Returns 'Done.' Instead of Rich Data
OpenClaw v Latestにおけるリグレッションで、/statusスラッシュコマンドが'Done.'テキストを表示し、期待されるrich埋め込みデータレスポンスの代わりに'Done.'と表示されます。
🔍 症状
/status Discordスラッシュコマンドがエラーをスローせずに実行されますが、期待されるリッチな埋め込みデータの代わりにプレーンテキストの「Done.」メッセージのみを返します。
CLI実行の例
コマンドが呼び出されると、ボットは最小限の出力で応答します:
User: /status
Bot: Done.
期待される応答(以前的動作):
User: /status
Bot: [ステータス情報、モデル情報、システムメトリクスなどを含むリッチな埋め込みメッセージ]
診断指標
- 終了コード:
0(コマンドは正常に完了) - コンソール出力にエラーログなし
- 応答は迅速に到着(タイムアウトなし)
- テキストチャンネルコンテキストではコマンドが動作するがDMコンテキストでは失敗
- Botは適切な
APPLICATION_COMMANDSパーミッションスコープを保持
二次的な症状
- インタラクションの認識が「Thinking…」と表示された後「Done.」に戻る場合がある
- 応答に埋め込みフォーマット、色、フィールドがない
- メッセージのタイムスタンプは正しい実行時刻を表示
- 後続のコマンドは正常に動作し続ける
🧠 原因
「Done.」という応答は、インタラクション応答が最初の認識後に適切に作成または編集されなかった場合のDiscord.jsデフォルトフォールバックメッセージです。
技術的な失敗シーケンス
- インタラクション受信: Discordが
INTERACTION_CREATEイベントをOpenClawハンドラーに送信 - 最初の認識: OpenClawがデフォルトのフォールバックとして
{ content: "Done." }でinteraction.reply()を呼び出す - ハンドラー実行: 実際のステータスハンドラーがデータの処理を開始
- 応答失敗: ハンドラーが
interaction.editReply()またはinteraction.followUp()を使用しようとする - コールバック解決の欠落: 応答がフォローアップメソッドに到達しない原因:
- ハンドラーチェーンでasync/awaitが適切にawaitされていない
- Promise rejectionがサイレントに飲み込まれる
- インタラクションオブジェクト参照が古くなる
- デフォルト表示: Discordが最初の「Done.」認識をレンダリング
アーキテクチャの不整合
OpenClawのDiscord adapterがインタラクションデфер応答の処理方法を変更しました:
以前(動作していた):
await interaction.reply({ embeds: [statusEmbed] });
以降(壊れている):
await interaction.deferReply(); // 「Done.」で暗黙的な認識
// ... 非同期処理 ...
await interaction.editReply({ embeds: [statusEmbed] }); // サイレントに失敗
ディファラルパターンはフォローアップ編集が正常に完了することを前提としています。処理チェーンの例外はすべて「Done.」が残り続けます。
影响を受ける特定のコードパス
src/adapters/discord/interaction-handler.ts: 応答編集周围的ty-catchが欠落src/commands/status/index.ts: ハンドラーがデータ取得を適切にawaitしない可能性があるsrc/providers/openclaw/status-service.ts: 特定の環境でデータ取得が例外をスローする可能性がある
🛠️ 解決手順
方法1: 同期応答を確実にする(推奨)
ステータスコマンドハンドラーをディファラルなしで直接応答するように修正します:
// 以前(リグレッションの原因)
statusCommand: async (interaction) => {
await interaction.deferReply();
const status = await fetchStatusData();
await interaction.editReply({ embeds: [buildEmbed(status)] });
}
// 以降(正しい)
statusCommand: async (interaction) => {
const status = await fetchStatusData();
await interaction.reply({ embeds: [buildEmbed(status)] });
}
方法2:堅牢なエラー処理を追加
非同期応答フローを包括的なエラー処理でラップします:
statusCommand: async (interaction) => {
await interaction.deferReply({ ephemeral: false }).catch(err => {
console.error('Defer failed:', err);
throw err; // サイレント失敗を防ぐために伝播
});
try {
const status = await fetchStatusData();
const embed = buildEmbed(status);
await interaction.editReply({ embeds: [embed] }).catch(err => {
console.error('EditReply failed:', err);
await interaction.reply({ embeds: [embed] }); // フォールバック
});
} catch (error) {
console.error('Status fetch failed:', error);
await interaction.editReply({
content: '⚠️ ステータス情報の取得に失敗しました。',
embeds: []
}).catch(() => {
await interaction.reply('⚠️ ステータス情報の取得に失敗しました。');
});
}
}
方法3: Adapter設定を確認
OpenClawセットアップでDiscord adapterが正しく設定されていることを確認します:
// openclaw.config.ts
export default {
adapters: {
discord: {
intents: ['Guilds', 'GuildMessages', 'DirectMessages'],
// 明示的に応答モードを設定
useLegacyContextMenus: false,
respondOnDefer: false // 暗黙的な「Done.」応答を無効化
}
}
}
方法4: スラッシュコマンド登録を確認
スラッシュコマンドを強制的に再登録して、適切な権限を確保します:
# 既存のコマンドを削除
npx openclaw discord commands delete status --guild YOUR_GUILD_ID
# グローバルキャッシュをクリア
npx openclaw discord cache clear
# 再登録
npx openclaw discord commands register
# 登録を確認
npx openclaw discord commands list
🧪 検証
テストコマンド
1. コマンド登録を確認:
npx openclaw discord commands list --verbose
# 期待:/statusコマンドが正しい説明とオプションとともに表示
2. 公開チャンネルでテスト:
# テキストチャンネルで(DMではなく)
/status
# 期待:すべてのユーザーに表示されるステータスデータを含むリッチな埋め込み
3. DMコンテキストでテスト:
# BotのDMで
/status
# 期待:ステータスデータを含むリッチな埋め込み
# それでも「Done.」が表示される場合:DM固有の処理に問題あり
4. デバッグログを有効化:
# 環境変数を設定
export LOG_LEVEL=debug
export DEBUG=openclaw:discord:*
# OpenClawを再起動
npx openclaw start
# /statusを実行してログを観察
# 確認対象:「interaction.reply」、「interaction.deferReply」、「interaction.editReply」
期待されるログ出力(修正済み状態)
[DEBUG] openclaw:discord:interaction - /status用のINTERACTION_CREATEを受信
[DEBUG] openclaw:discord:interaction - ステータスハンドラーを呼び出し
[DEBUG] openclaw:discord:interaction - プロバイダーからステータスを取得中
[DEBUG] openclaw:discord:interaction - 5つのフィールドで埋め込みを構築
[INFO] openclaw:discord:interaction - 埋め込みでインタラクションに応答
[DEBUG] openclaw:discord:interaction - 応答を送信:200 OK
終了コードの検証
# 検証テスト実行後
echo $?
# 期待:0(成功)
⚠️ よくある落とし穴
環境固有のトラップ
- WSL2のタイミング問題: WSL2のクロック同期によりインタラクション応答がタイムアウトする可能性があります。Discordのインタラクションは3秒以内に応答する必要があります。
ntpdまたはwsl2-hibernate回避策を使用してください。 - Dockerコンテナのタイムアウト: Dockerで実行している場合、コンテナクロックがホストと一致していることを確認してください。
docker run --cap-add=SYS_TIMEを実行するか、timedatectl set-ntp trueで同期してください。 - Windows Defender ファイアウォール: DMコンテキストでWebSocket接続をブロックする可能性があります。Discordのgateway IPに例外を追加してください。
設定の誤り
- Intentsの欠落:
GuildsintentなしではDMインタラクションが適切に登録されない可能性があります - Ephemeralデフォルト: 一部の設定は
ephemeral: trueがデフォルトで、予期しない場所に「Done.」が表示される原因となります - 古いキャッシュ: ローカルにキャッシュされた古いコマンド定義が登録更新を上書きする可能性があります
ハンドラーのアンチパターン
- 非同期呼び出しのawait忘れ:
// 間違い interaction.deferReply(); fetchStatusData().then(data => { interaction.editReply({ embeds: [data] }); // 'this'コンテキストが失われる });// 正しい await interaction.deferReply(); const data = await fetchStatusData(); await interaction.editReply({ embeds: [data] });
- 飲み込まれる例外: 空のcatchブロックがデバッグを防ぎます
// 間違い try { ... } catch (e) {}// 正しい try { … } catch (e) { console.error(‘ステータスコマンドが失敗しました:’, e); throw e; // または適切に処理 }
- 競合状態: 複数のRapidコマンド呼び出しが共有状態と競合する可能性があります
モデル/プロバイダーのエッジケース
- Opus 4.6固有: 一部のデータフィールドはモデルコンテキストがコールドの場合に
nullになる可能性があり、埋め込み構築がサイレントに失敗する原因となります - レート制限: Discord DMインタラクションにはより厳しいレート制限があり、リクエストデバウンスを確保してください
🔗 関連するエラー
InteractionNotReplied: 送信されなかった返信を編集しようとしたときにスローされます。「Unknown Message」Discord APIエラーとして現れます。50027: Invalid WebSocket State: インタラクションは到着しましたが、応答送信前に接続が閉じられました。40060: Interaction Already Acknowledged:deferReply()後にreply()を呼び出そうとし、editReply()を使用しませんでした。50013: Missing Permissions: BotがSEND_MESSAGESまたはEMBED_LINKSパーミッションを欠いており、埋め込みの失敗原因となっています。- #2847: Slash command ephemeral setting ignored in DMs: OpenClaw adapterに影響する関連するDiscord API動作変更。
- #3156: deferReply() silently fails on cold start: 競合状態を引き起こす非同期ハンドラー初期化。
- #3291: Status command regression after v2.3.0 adapter update: この正確なリグレッションパターンの直接的な前身。