Skip to content

Telegram channel broken after upgrading to 2026.3.x — undici bypasses macOS TUN/VPN #33013

@obuhc

Description

@obuhc

Telegram channel broken after upgrading to 2026.3.x — undici bypasses macOS TUN/VPN

Environment

  • OpenClaw version: 2026.3.2 (regression; works fine on 2026.2.26)
  • OS: macOS 15.5 (arm64, Apple Silicon)
  • Node.js: v24.11.1
  • VPN: Outline VPN (TUN mode — captures all system traffic at the network interface level)
  • Telegram bot library: grammy (via undici fetch)
  • Install method: npm (npm install -g openclaw)
  • Gateway mode: LaunchAgent (ai.openclaw.gateway)

Summary

After upgrading from 2026.2.26 to 2026.3.x, the Telegram channel fails to connect with repeated Network request for '<method>' failed! errors. All Telegram Bot API calls (deleteWebhook, deleteMyCommands, setMyCommands, polling) fail immediately on gateway startup.

Rolling back to 2026.2.26 resolves the issue completely.

Symptoms

On gateway startup, the following errors repeat in a loop every ~30 seconds:

error gateway/channels/telegram telegram deleteWebhook failed: Network request for 'deleteWebhook' failed!
error gateway/channels/telegram Telegram webhook cleanup failed: Network request for 'deleteWebhook' failed!; retrying in 7.63s.
error gateway/channels/telegram telegram deleteMyCommands failed: Network request for 'deleteMyCommands' failed!
error gateway/channels/telegram telegram setMyCommands failed: Network request for 'setMyCommands' failed!
error gateway/channels/telegram Telegram command sync failed: HttpError: Network request for 'setMyCommands' failed!

The Telegram channel shows status: WARN │ failed (unknown) - This operation was aborted

Root Cause Analysis

Through debugging, I identified that the 2026.3.x Telegram module switched its HTTP client from Node.js native fetch to undici (import { fetch } from "undici"), specifically in:

  • dist/proxy-fetch-DrI0Gh6p.js — uses undici.ProxyAgent and undici.EnvHttpProxyAgent
  • dist/send-BfbOwTR-.jsresolveTelegramFetch() resolves to undici-based fetch

undici maintains its own network stack and DNS resolution, which bypasses macOS's TUN-mode VPN tunnel. This means:

Client Uses system network stack Goes through TUN VPN Result
curl ✅ Yes ✅ Yes ✅ HTTP 200
Node.js native https.get ✅ Yes ✅ Yes ✅ HTTP 200
Node.js native fetch ✅ Yes ✅ Yes ✅ HTTP 200
undici fetch ❌ Own stack ❌ Bypasses TUN ❌ Network request failed

Verification

From the same terminal session where openclaw gateway was running:

# Native curl — works
$ curl -sS https://api.telegram.org/bot<token>/getMe
{"ok":true,"result":{"id":...,"is_bot":true,...}}

# Node.js native https — works
$ node -e "require('https').get('https://api.telegram.org/bot<token>/getMe', r => { let d=''; r.on('data',c=>d+=c); r.on('end',()=>console.log(d)) })"
{"ok":true,"result":{"id":...,"is_bot":true,...}}

# But OpenClaw gateway (using undici) — fails
error gateway/channels/telegram telegram deleteWebhook failed: Network request for 'deleteWebhook' failed!

Workaround

Option 1: Rollback to 2026.2.26 (confirmed working)

npm install -g [email protected]
openclaw gateway restart

Option 2: Local HTTP CONNECT proxy (forces undici through system network)

Create a minimal local proxy that uses Node.js native net.connect (which respects TUN):

// ~/.openclaw/telegram-proxy.mjs
import { createServer } from 'node:http';
import { connect } from 'node:net';

const PORT = 18800;
const server = createServer();
server.on('connect', (req, clientSocket, head) => {
  const [host, port] = req.url.split(':');
  const serverSocket = connect(parseInt(port) || 443, host, () => {
    clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
    if (head.length) serverSocket.write(head);
    serverSocket.pipe(clientSocket);
    clientSocket.pipe(serverSocket);
  });
  serverSocket.on('error', () => clientSocket.destroy());
  clientSocket.on('error', () => serverSocket.destroy());
});
server.listen(PORT, '127.0.0.1');

Then configure in openclaw.json:

{
  "channels": {
    "telegram": {
      "proxy": "http://127.0.0.1:18800"
    }
  }
}

Expected Behavior

The Telegram channel should work with TUN-mode VPNs (Outline, WireGuard, etc.) without requiring an explicit proxy configuration, as it did in 2026.2.26.

Suggested Fix

Consider one of the following:

  1. Use Node.js native fetch (available since Node 18+) instead of undici's fetch for Telegram API calls. Native fetch respects the OS network stack and TUN routing.

  2. Fall back to native fetch when undici fails — detect the "Network request failed" error pattern and automatically retry with globalThis.fetch.

  3. Respect NODE_USE_SYSTEM_CA and system network settings — if the environment indicates system-level networking should be used, prefer the native stack.

  4. Document the channels.telegram.proxy workaround for users in restricted network environments.

Affected Versions

  • Broken: 2026.3.1, 2026.3.2
  • Working: 2026.2.26 and earlier

Additional Context

  • This affects any user behind a TUN-mode VPN (common in China, corporate networks, etc.)
  • The issue is not specific to Telegram — any OpenClaw module that switched to undici may have the same problem
  • macOS LaunchAgent-started gateway processes are especially affected since they don't inherit user shell proxy environment variables

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions