April 24, 2026 โ€ข Version: 2026.2.26

Discord REST API Fails with Proxy Despite WebSocket Success

The `channels.discord.proxy` configuration only applies to WebSocket gateway connections, not to outbound REST API calls. This causes fetch failures when sending messages in restricted regions.

๐Ÿ” Symptoms

Primary Symptom

Discord bot receives messages successfully but fails to send them, throwing a TypeError: fetch failed error.

Technical Manifestations

Log Output Pattern: 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 Diagnostic Commands

bash

Verify Discord connection status

openclaw debug channels

Test proxy connectivity

curl -x http://127.0.0.1:7890/ https://discord.com/api/v10/gateway

Check if REST calls bypass proxy

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

Configuration that Appears Correct but Fails

yaml channels: discord: enabled: true token: “Bot xxx…” proxy: “http://127.0.0.1:7890/” # WebSocket uses this # No REST proxy override available

๐Ÿง  Root Cause

Architectural Issue: Dual Network Paths

OpenClaw’s Discord channel implementation uses two distinct network paths:

Operation TypeNetwork PathProxy Support
Gateway Connection (WebSocket)discord.io WebSocket clientโœ… Respects channels.discord.proxy
REST API Calls (send message, upload attachment, etc.)carbon-request RequestClientโŒ No proxy support

Code Flow Analysis

User sends message to Discord โ†“ OpenClaw receives via WebSocket (โœ“ proxied) โ†“ Bot processes and needs to reply โ†“ RequestClient.sendMessage() called โ†“ fetch() executes WITHOUT proxy agent โ†“ TypeError: fetch failed (connection refused/timeout)

Specific File Involvement

The root cause resides in how carbon-request / RequestClient is invoked in the Discord channel handler:

javascript // In discord-channel.js (simplified) async function sendReply(message) { const client = new RequestClient(); // No agent passed return client.post({ url: https://discord.com/api/v10/channels/${channelId}/messages, body: { content: message } }); // Direct connection, no proxy }

The channels.discord.proxy setting is only consumed by the WebSocket initialization code path, never by the REST request handler.

Why It Works for Receiving

The WebSocket frame handling correctly passes the proxy agent: javascript const ws = new WebSocket(url, { agent: new HttpsProxyAgent(proxyUrl) // โœ… Proxy applied });

Why It Fails for Sending

The REST call creates a direct connection: javascript // carbon-request internal (simplified) function request(options) { return fetch(options.url, { // No agent configuration for proxy }); }

๐Ÿ› ๏ธ Step-by-Step Fix

Option 1: Environment Variable Override (Workaround - Immediate)

Set global proxy environment variables before launching 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/”

Then start OpenClaw

openclaw start

Before vs After:

SettingBeforeAfter
channels.discord.proxyWebSocket onlyWebSocket only
Environment variablesNot setAll traffic proxied

Option 2: Code-level Fix (Permanent - Requires Patching)

Create a wrapper module that applies proxy to all HTTP requests:

Step 1: Install required dependency bash npm install https-proxy-agent –save

Step 2: Create proxy-aware RequestClient wrapper javascript // File: ~/.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, // Force HTTPS for Discord API protocol: ‘https:’ }); }

get(options) { return super.get({ …options, agent: this.agent }); }

post(options) { return super.post({ …options, agent: this.agent }); } }

module.exports = { ProxyRequestClient };

Step 3: Patch Discord channel to use wrapper javascript // In discord-channel.js, modify initialization: // Find: const client = new RequestClient(); // Replace with: const proxyUrl = config.get(‘channels.discord.proxy’) || process.env.HTTPS_PROXY; const client = proxyUrl ? new ProxyRequestClient(proxyUrl) : new RequestClient();

Option 3: Replace carbon-request with proxy-aware client

Step 1: Install node-fetch with agent support bash npm install node-fetch@2 https-proxy-agent@5 –save

Step 2: Replace RequestClient usage in Discord channel javascript // Replace all RequestClient imports with: const fetch = require(’node-fetch’); const { HttpsProxyAgent } = require(‘https-proxy-agent’);

// In sendMessage function: 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(); }

๐Ÿงช Verification

Test 1: Verify WebSocket Proxy (Should Already Work)

bash openclaw debug –channel discord –verbose 2>&1 | grep -i proxy

Expected Output: log [INFO] Discord gateway connecting via proxy: http://127.0.0.1:7890/ [INFO] Discord gateway connected (WebSocket)

Test 2: Verify REST Proxy (The Actual Fix)

javascript // Save as test-discord-rest.js const { HttpsProxyAgent } = require(‘https-proxy-agent’);

async function testProxyRequest() { const proxyUrl = ‘http://127.0.0.1:7890’;

// Test without proxy (should fail in restricted region) 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); }

// Test with proxy (should succeed) 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();

Run with: bash node test-discord-rest.js

Test 3: End-to-End Discord Message Send

bash

Start OpenClaw with proxy

HTTP_PROXY=“http://127.0.0.1:7890” HTTPS_PROXY=“http://127.0.0.1:7890” openclaw start

In another terminal, send test message via Discord

Send “!test” to your bot

Check logs

tail -f ~/.openclaw/logs/openclaw.log | grep -E “(discord|message|proxy|error)”

Expected Success Pattern: log [INFO] Discord gateway connected via proxy [INFO] Received: !test [INFO] Sending reply via REST (proxied) [INFO] Reply sent successfully (200 OK)

Test 4: Verify No fetch failed Error

bash

After fix, this should not appear

grep -r “fetch failed” ~/.openclaw/logs/

Expected: No matches (empty result)

โš ๏ธ Common Pitfalls

Pitfall 1: Mixing HTTP/HTTPS Proxy Protocols

Discord API requires HTTPS. Ensure your proxy configuration uses HTTPS:

โŒ Wrongโœ… Correct
http://127.0.0.1:7890/ for gatewayUse for both (node handles upgrade)
SOCKS proxy without agent configInstall socks-proxy-agent explicitly

javascript // For SOCKS proxies: const { SocksProxyAgent } = require(‘socks-proxy-agent’); const agent = new SocksProxyAgent(‘socks://127.0.0.1:1080’);

Pitfall 2: Environment Variable Scoping

Environment variables set after process start don’t apply. Always set before launching:

bash

โœ— Wrong - vars not inherited

openclaw start && export HTTP_PROXY="…"

โœ“ Correct - vars set before fork

HTTP_PROXY="…" openclaw start

Pitfall 3: Node.js Version Compatibility

https-proxy-agent@5+ requires Node.js 18+. For older versions:

bash node –version

If < 18, use: npm install https-proxy-agent@4

Pitfall 4: Proxy Authentication Not Handled

If your proxy requires username/password:

javascript const proxyUrl = ‘http://user:[email protected]:7890/’; // or const proxyUrl = ‘http://’ + encodeURIComponent(‘user’) + ‘:’ + encodeURIComponent(‘pass’) + ‘@127.0.0.1:7890/’;

Pitfall 5: TLS Certificate Errors

In some proxy configurations, you may need to disable SSL verification for testing:

javascript process.env.NODE_TLS_REJECT_UNAUTHORIZED = ‘0’;

โš ๏ธ Warning: Only use this for debugging. Never in production.

Pitfall 6: Docker Container Proxy Isolation

If running OpenClaw in Docker, proxy must be accessible from within the container:

bash

โœ— Container can’t reach host loopback

HTTP_PROXY=“http://127.0.0.1:7890”

โœ“ Use host network or docker.for.mac.localhost

HTTP_PROXY=“http://host.docker.internal:7890

For Docker, add --network=host or configure network_mode: host in docker-compose.

Logically Connected Error Patterns

ErrorDescriptionRelated To
TypeError: fetch failedREST call connection failureThis issue
ECONNREFUSEDProxy server not runningNetwork/proxy availability
ETIMEDOUTConnection timeout to DiscordNetwork/firewall blocking
ENOTFOUNDCannot resolve Discord DNSDNS filtering in restricted regions
Failed to connect to Discord gatewayWebSocket init failureProxy not applied to WS client
Disconnected with code 1006WebSocket abnormal closureNetwork instability/proxy dropping
Request timeoutREST request hangingProxy slow/unstable

Historical Context

  • Issue #1423: WebSocket proxy support added for Discord gateway
  • Issue #1891: Media/attachment downloads bypass proxy
  • Issue #2156: carbon-request client lacks agent injection API

Similar Patterns in Other Channels

ChannelHas REST Proxy IssueWorkaround
Discordโœ… Yes (this issue)Env vars / code patch
Slackโš ๏ธ PartialUses node-fetch with agent
TeamsโŒ UnknownRequires testing
MattermostโŒ UnknownRequires testing

Evidence & Sources

This troubleshooting guide was automatically synthesized by the FixClaw Intelligence Pipeline from community discussions.