[プロキシ使用時のDiscord REST API失敗] - Discord REST API Fails with Proxy Despite WebSocket Success
`channels.discord.proxy`設定はWebSocketゲートウェイ接続のみに適用され、アウトバウンドREST API呼び出しには適用されません。これにより、制限された地域でメッセージを送信する際のフェッチエラーが発生します。
🔍 症状
主な症状
Discordボットのメッセージ受信は成功するが、送信に失敗し、TypeError: fetch failedエラーが発生する。
技術的な症状
ログ出力パターン: log [2026-02-26 10:23:45] INFO: Discord gateway connected via proxy ws://127.0.0.1:7890/ [2026-02-26 10:23:52] INFO: Received message from user123 [2026-02-26 10:23:52] ERROR: discord final reply failed: TypeError: fetch failed [2026-02-26 10:23:52] ERROR: at fetch (node:internal/deps:node_fetch:index.js:…) at async RequestClient.request (…)
CLI診断コマンド
bash
Discord接続状態を確認
openclaw debug channels
プロキシ接続性をテスト
curl -x http://127.0.0.1:7890/ https://discord.com/api/v10/gateway
REST呼び出しがプロキシをバイパスするか確認
node -e " const fetch = require(’node-fetch’); fetch(‘https://discord.com/api/v10/gateway', { agent: new (require(‘http-proxy-agent’))(‘http://127.0.0.1:7890’) }).then(r => console.log(‘Proxy works:’, r.status)).catch(e => console.error(‘Failed:’, e.message)); "
正しく見えるが失敗する設定
yaml channels: discord: enabled: true token: “Bot xxx…” proxy: “http://127.0.0.1:7890/” # WebSocketはこれを使用 # RESTプロキしのオーバーライドは利用不可
🧠 原因
アーキテクチャ上の問題:二重ネットワークパス
OpenClawのDiscordチャンネル実装は、2つの異なるネットワークパスを使用します:
| 操作タイプ | ネットワークパス | プロキシサポート |
|---|---|---|
| Gateway接続(WebSocket) | discord.io WebSocketクライアント | ✅ channels.discord.proxyを尊重 |
| REST API呼び出し(メッセージ送信、添付ファイルアップロード等) | carbon-request RequestClient | ❌ プロキシサポートなし |
コードフロー分析
ユーザーがDiscordにメッセージを送信 ↓ OpenClawがWebSocket経由で受信(✓ プロキシ経由) ↓ ボットが処理して返信が必要 ↓ RequestClient.sendMessage()呼び出し ↓ fetch()がプロキシエージェントなしで実行 ↓ TypeError: fetch failed(接続拒否/タイムアウト)
関連するファイル
根本原因は、carbon-request / RequestClientがDiscordチャンネルハンドラーでどのように呼び出されるかにあります:
javascript
// discord-channel.js内(簡略化)
async function sendReply(message) {
const client = new RequestClient(); // agentが渡されていない
return client.post({
url: https://discord.com/api/v10/channels/${channelId}/messages,
body: { content: message }
}); // 直接接続、プロキシなし
}
channels.discord.proxy設定は、WebSocket初期化コードパスでのみ使用され、RESTリクエストハンドラーでは使用されません。
受信が機能する理由
WebSocketフレーム処理は正しくプロキシエージェントを渡します: javascript const ws = new WebSocket(url, { agent: new HttpsProxyAgent(proxyUrl) // ✅ プロキシが適用される });
送信が失敗する理由
REST呼び出しは直接接続を作成します: javascript // carbon-request内部(簡略化) function request(options) { return fetch(options.url, { // プロキシ用のagent設定がない }); }
🛠️ 解決手順
オプション1:環境変数のオーバーライド(回避策 - 即時対応)
OpenClawを起動する前にグローバルプロキシ環境変数を設定します:
bash
Linux/macOS
export HTTP_PROXY=“http://127.0.0.1:7890/” export HTTPS_PROXY=“http://127.0.0.1:7890/” export http_proxy=“http://127.0.0.1:7890/” export https_proxy=“http://127.0.0.1:7890/”
次にOpenClawを起動
openclaw start
変更前と変更後:
| 設定 | 変更前 | 変更後 |
|---|---|---|
channels.discord.proxy | WebSocketのみ | WebSocketのみ |
| 環境変数 | 未設定 | 全トラフィックがプロキシ経由 |
オプション2:コードレベルの修正(恒久対応 - パッチ適用が必要)
すべてのHTTPリクエストにプロキシを適用するラッパーモジュールを作成します:
ステップ1: 必要な依存関係をインストール bash npm install https-proxy-agent –save
ステップ2: プロキシ対応のRequestClientラッパーを作成 javascript // ファイル: ~/.openclaw/plugins/proxy-request-wrapper.js
const { RequestClient } = require(‘carbon-request’); const { HttpsProxyAgent } = require(‘https-proxy-agent’);
class ProxyRequestClient extends RequestClient { constructor(proxyUrl) { super(); this.proxyUrl = proxyUrl; this.agent = new HttpsProxyAgent(proxyUrl); }
request(options) { return super.request({ …options, agent: this.agent, // Discord API用にHTTPSを強制 protocol: ‘https:’ }); }
get(options) { return super.get({ …options, agent: this.agent }); }
post(options) { return super.post({ …options, agent: this.agent }); } }
module.exports = { ProxyRequestClient };
ステップ3: Discordチャンネルを修正してラッパーを使用 javascript // discord-channel.jsで、初期化を修正: // 検索: const client = new RequestClient(); // 置換: const proxyUrl = config.get(‘channels.discord.proxy’) || process.env.HTTPS_PROXY; const client = proxyUrl ? new ProxyRequestClient(proxyUrl) : new RequestClient();
オプション3:carbon-requestをプロキシ対応クライアントに置き換える
ステップ1: agentサポート付きでnode-fetchをインストール bash npm install node-fetch@2 https-proxy-agent@5 –save
ステップ2: DiscordチャンネルのRequestClient使用箇所を置き換え javascript // すべてのRequestClientインポートを以下で置き換え: const fetch = require(’node-fetch’); const { HttpsProxyAgent } = require(‘https-proxy-agent’);
// sendMessage関数内: async function sendMessage(channelId, content) { const proxyUrl = process.env.HTTPS_PROXY || config.channels?.discord?.proxy;
const options = {
method: ‘POST’,
headers: {
‘Authorization’: Bot ${config.channels.discord.token},
‘Content-Type’: ‘application/json’
},
body: JSON.stringify({ content })
};
if (proxyUrl) { options.agent = new HttpsProxyAgent(proxyUrl); }
const response = await fetch(
https://discord.com/api/v10/channels/${channelId}/messages,
options
);
return response.json(); }
🧪 検証
テスト1:WebSocketプロキシの確認(すでに機能しているはず)
bash openclaw debug –channel discord –verbose 2>&1 | grep -i proxy
期待される出力: log [INFO] Discord gateway connecting via proxy: http://127.0.0.1:7890/ [INFO] Discord gateway connected (WebSocket)
テスト2:RESTプロキシの確認(実際の修正確認)
javascript // test-discord-rest.jsとして保存 const { HttpsProxyAgent } = require(‘https-proxy-agent’);
async function testProxyRequest() { const proxyUrl = ‘http://127.0.0.1:7890’;
// プロキシなしテスト(制限された地域では失敗するはず) try { await fetch(‘https://discord.com/api/v10/gateway'); console.log(’✗ Direct connection succeeded (unexpected)’); } catch (e) { console.log(’✓ Direct connection blocked as expected:’, e.message); }
// プロキシありテスト(成功するはず) try { const response = await fetch(‘https://discord.com/api/v10/gateway', { agent: new HttpsProxyAgent(proxyUrl) }); console.log(’✓ Proxy connection succeeded, status:’, response.status); } catch (e) { console.log(’✗ Proxy connection failed:’, e.message); } }
testProxyRequest();
実行: bash node test-discord-rest.js
テスト3:エンドツーエンドのDiscordメッセージ送信テスト
bash
プロキシ付きでOpenClawを起動
HTTP_PROXY=“http://127.0.0.1:7890” HTTPS_PROXY=“http://127.0.0.1:7890” openclaw start
別のターミナルで、Discord経由でテストメッセージを送信
ボットに"!test"を送信
ログを確認
tail -f ~/.openclaw/logs/openclaw.log | grep -E “(discord|message|proxy|error)”
成功パターンの例: log [INFO] Discord gateway connected via proxy [INFO] Received: !test [INFO] Sending reply via REST (proxied) [INFO] Reply sent successfully (200 OK)
テスト4:fetch failedエラーがないことを確認
bash
修正後、これは表示されないはず
grep -r “fetch failed” ~/.openclaw/logs/
期待結果: 一致なし(空の結果)
⚠️ よくある落とし穴
落とし穴1:HTTP/HTTPSプロキシプロトコルの混用
Discord APIはHTTPSが必要です。プロキシ設定でHTTPSを使用していることを確認してください:
| ❌ 間違い | ✅ 正しい |
|---|---|
gateway用 http://127.0.0.1:7890/ | 両方中使用(nodeがアップグレードを処理) |
| agent設定なしのSOCKSプロキシ | socks-proxy-agentを明示的にインストール |
javascript // SOCKSプロキシの場合: const { SocksProxyAgent } = require(‘socks-proxy-agent’); const agent = new SocksProxyAgent(‘socks://127.0.0.1:1080’);
落とし穴2:環境変数のスコープ
プロセスの起動後に設定された環境変数は適用されません。起動前に常に設定してください:
bash
✗ 間違い - 変数が継承されない
openclaw start && export HTTP_PROXY="…"
✓ 正しい - fork前に変数を設定
HTTP_PROXY="…" openclaw start
落とし穴3:Node.jsバージョンの互換性
https-proxy-agent@5+はNode.js 18+が必要です。古いバージョンの場合:
bash node –version
18未満の場合は: npm install https-proxy-agent@4
落とし穴4:プロキシ認証の処理
プロキシにユーザー名/パスワードが必要な場合:
javascript const proxyUrl = ‘http://user:pass@127.0.0.1:7890/’; // または const proxyUrl = ‘http://’ + encodeURIComponent(‘user’) + ‘:’ + encodeURIComponent(‘pass’) + ‘@127.0.0.1:7890/’;
落とし穴5:TLS証明書エラー
一部のプロキシ設定では、テスト用にSSL検証を無効にする必要がある場合があります:
javascript process.env.NODE_TLS_REJECT_UNAUTHORIZED = ‘0’;
⚠️ 警告: これはデバッグ専用にのみ使用してください。本番環境では使用しないでください。
落とし穴6:Dockerコンテナの プロキシ隔離
DockerでOpenClawを実行している場合、プロキシはコンテナ内からアクセス可能でなければなりません:
bash
✗ コンテナがホストのループバックに到達できない
HTTP_PROXY=“http://127.0.0.1:7890”
✓ ホストネットワークまたはdocker.for.mac.localhostを使用
HTTP_PROXY=“http://host.docker.internal:7890”
Dockerの場合、--network=hostを追加するか、docker-composeでnetwork_mode: hostを設定します。
🔗 関連するエラー
論理的に関連するエラーパターン
| エラー | 説明 | 関連性 |
|---|---|---|
TypeError: fetch failed | REST呼び出しの接続失敗 | この問題 |
ECONNREFUSED | プロキシサーバーが起動していない | ネットワーク/プロキシ可用性 |
ETIMEDOUT | Discordへの接続タイムアウト | ネットワーク/ファイアウォールがブロック |
ENOTFOUND | Discord DNS解決不可 | 制限された地域でのDNSフィルタリング |
Failed to connect to Discord gateway | WebSocket初期化失敗 | WSクライアントにプロキシが適用されない |
Disconnected with code 1006 | WebSocket異常終了 | ネットワーク不安定/プロキシ切断 |
Request timeout | RESTリクエストがハング | プロキシ遅い/不安定 |
歴史的背景
- Issue #1423: Discord gatewayのWebSocketプロキシサポートが追加
- Issue #1891: メディア/添付ファイルのダウンロードがプロキシをバイパス
- Issue #2156: carbon-requestクライアントにagent注入APIがない
他のチャンネルでの類似パターン
| チャンネル | RESTプロキシ問題あり | 回避策 |
|---|---|---|
| Discord | ✅ はい(この問題) | 環境変数 / コードパッチ |
| Slack | ⚠️ 一部 | agent付きでnode-fetchを使用 |
| Teams | ❌ 不明 | テストが必要 |
| Mattermost | ❌ 不明 | テストが必要 |