openclaw - ✅(Solved) Fix [Bug]: Global fetch interceptor injects Symbol(sensitiveHeaders), breaking discord.js (undici) on Node.js 22 [2 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#77846Fetched 2026-05-06 06:20:23
View on GitHub
Comments
1
Participants
2
Timeline
5
Reactions
2
Timeline (top)
cross-referenced ×2labeled ×2commented ×1

When attempting to use discord.js (v14.x) inside an OpenClaw plugin on Node.js 22, the Discord client immediately crashes during client.login() or any REST API call.

The crash is caused by OpenClaw's global fetch interceptor mutating the init.headers object by injecting a hidden Symbol (Symbol(sensitiveHeaders)). In Node.js 22, the native undici fetch engine strictly validates the Headers initialization object and immediately throws a TypeError if it encounters any non-string Symbol keys.

Error Message

[plugins] Plugin init error: Headers constructor: Key Symbol(sensitiveHeaders) in init is a symbol, which cannot be converted to a ByteString.

Root Cause

The crash is caused by OpenClaw's global fetch interceptor mutating the init.headers object by injecting a hidden Symbol (Symbol(sensitiveHeaders)). In Node.js 22, the native undici fetch engine strictly validates the Headers initialization object and immediately throws a TypeError if it encounters any non-string Symbol keys.

Fix Action

Fix / Workaround

CURRENT WORKAROUND

PR fix notes

PR #77963: fix(net): sanitize HeadersInit to prevent Symbol-keyed header crashes on Node 22

Description (problem / solution / changelog)

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem: Node.js 22's native undici engine throws a TypeError when a HeadersInit object contains Symbol keys (e.g., Symbol(sensitiveHeaders)).
  • Why it matters: This prevents standard libraries like discord.js from initializing or making network requests within OpenClaw plugins, as OpenClaw's global fetch interceptors inadvertently pass these Symbols to the native Headers constructor.
  • What changed: Introduced a sanitizeHeadersInit utility to strip non-string keys before they reach new Headers() or native fetch() calls.
  • What did NOT change (scope boundary): The core network dispatching logic and existing header values remain untouched; only the initialization object keys are normalized.

Change Type

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue

  • ISSUE
  • This PR fixes a bug .

Real behavior proof

  • Behavior or issue addressed: Fixed "ByteString" conversion error on Node 22 when using fetch-heavy plugins.
  • Real environment tested: WSL2 (Ubuntu) running Node.js v22.1.0.
  • Exact steps or command run after this patch: Executed a standalone script that passes a Symbol-keyed record to the patched Headers initialization flow.
  • Evidence after fix:
ayu@MSI:~/openclaw-main$ npx tsx scratch/ultimate_proof.ts
💎 STARTING ULTIMATE BEHAVIOR PROOF...
Testing against a REAL library (discord.js v14) through OpenClaw core.

Attempting discord.js client.login()...
(This normally crashes OpenClaw on Node 22 due to Symbol(sensitiveHeaders))

✅ ULTIMATE PROOF SUCCESS!
   The request successfully passed through OpenClaw's Headers constructor.
   Received standard Discord error: 'An invalid token was provided.'
<img width="966" height="252" alt="Screenshot 2026-05-06 002616" src="https://github.com/user-attachments/assets/6c7d01b6-0735-4077-8afe-c4ca8c26534b" />

-> Observed result after fix: Native Headers constructor accepts the sanitized object and correctly retrieves string-keyed headers. -> What was not tested: Performance impact on extremely high-frequency fetch calls (though overhead is minimal).

ROOT CAUSE

-> Root cause: Node.js 22's undici implementation strictly validates HeadersInit keys. OpenClaw's proxy-capture and runtime-fetch layers were passing objects containing internal tracking Symbols to this constructor. -> Missing detection / guardrail: Lack of normalization at the boundary between OpenClaw's interceptors and the native fetch runtime.

BEHAVIOR CHANGE

Before:
[Plugin Fetch] -> [OpenClaw Interceptor (Adds Symbol)] -> [Native Headers(init)] -> ❌ CRASH

After:
[Plugin Fetch] -> [OpenClaw Interceptor] -> [sanitizeHeadersInit()] -> [Native Headers(init)] -> ✅ SUCCESS

Environment

  • OS: WSL2 (Ubuntu)
  • Runtime/container: Node.js v22.1.0
  • Model/provider: google
  • Integration/channel (if any): discord.js v14

MY TEST FILE (ultimate_proof.ts)

// @ts-ignore
import { Client, GatewayIntentBits } from "discord.js";

async function ultimateProof() {
  console.log("💎 STARTING ULTIMATE BEHAVIOR PROOF...");
  console.log("Testing against a REAL library (discord.js v14) through OpenClaw core.\n");

  // Initialize a real Discord client (which uses fetch internally)
  const client = new Client({ intents: [GatewayIntentBits.Guilds] });

  console.log("Attempting discord.js client.login()...");
  console.log("(This normally crashes OpenClaw on Node 22 due to Symbol(sensitiveHeaders))\n");

  try {
    // We use a fake token. 
    // BEFORE: This would throw the 'ByteString' conversion error immediately.
    // AFTER: It should proceed past the Headers constructor and only fail with 
    //        a standard 'An invalid token was provided' error from Discord.
    await client.login("MTEyMjMzNDQ1NTY2Nzc4ODk5MA.G1A2B3.C4D5E6F7G8H9I0J1K2L3M4N5O6P7Q8R9S0T1U");
  } catch (err: any) {
    if (err.message.includes("ByteString") || err.message.includes("symbol")) {
      console.error("❌ PROOF FAILED: The ByteString crash still occurs!");
      console.error(err.message);
      (globalThis as any).process.exit(1);
    } else if (err.message.includes("An invalid token was provided")) {
      console.log("✅ ULTIMATE PROOF SUCCESS!");
      console.log("   The request successfully passed through OpenClaw's Headers constructor.");
      console.log("   Received standard Discord error: 'An invalid token was provided.'");
    } else {
      console.log("   Received unexpected error (but not the crash):", err.message);
    }
  }
}

ultimateProof().catch(console.error);

Changed files

  • src/infra/net/fetch-guard.ts (modified, +5/-2)
  • src/infra/net/proxy-fetch.ts (modified, +2/-1)
  • src/infra/net/redirect-headers.ts (modified, +16/-1)
  • src/infra/net/runtime-fetch.ts (modified, +2/-1)
  • src/proxy-capture/runtime.ts (modified, +4/-0)

PR #78058: fix: strip symbol keys from fetch headers

Description (problem / solution / changelog)

Summary

Fixes the fetch wrapper boundary so plain header dictionaries carrying enumerable symbol metadata are cloned with only string-keyed headers before being forwarded to native fetch/undici. This prevents Node 22's Headers constructor from crashing on symbol keys such as Symbol(sensitiveHeaders) while avoiding mutation of caller-owned header objects.

Changes

  • Sanitizes only plain-object init.headers values with enumerable symbol keys in wrapFetchWithAbortSignal.
  • Preserves Headers, tuple-array headers, and plain header objects without symbol keys unchanged.
  • Adds regression coverage for symbol-keyed header dictionaries and the pass-through case.

Testing

  • PATH="/tmp/openclaw-pnpm-shim:$PATH" pnpm vitest run src/infra/fetch.test.ts — passed, 18 tests.
  • git diff --check — passed.
  • PATH="/tmp/openclaw-pnpm-shim:$PATH" node scripts/check-changed.mjs — ran all gates through pairing account guard, then process was SIGKILLed at exit/final step; standalone PATH="/tmp/openclaw-pnpm-shim:$PATH" node scripts/check-pairing-account-scope.mjs passed immediately.

Fixes #77846

Changed files

  • src/infra/fetch.test.ts (modified, +28/-0)
  • src/infra/fetch.ts (modified, +36/-1)

Code Example

[plugins] Plugin init error: Headers constructor: Key Symbol(sensitiveHeaders) in init is a symbol, which cannot be converted to a ByteString.

---

import { Client, GatewayIntentBits } from "discord.js";

export default definePluginEntry({
  id: "discord_test",
  register(api) {
    const client = new Client({ intents: [GatewayIntentBits.Guilds] });
    // Crashes here during the internal fetch call
    client.login("BOT_TOKEN_HERE").catch(console.error);
  }
});

---

<img width="1449" height="68" alt="Image" src="https://github.com/user-attachments/assets/25506082-faca-48c4-a9cf-7799c4182da4" />
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

Yes

Summary

When attempting to use discord.js (v14.x) inside an OpenClaw plugin on Node.js 22, the Discord client immediately crashes during client.login() or any REST API call.

The crash is caused by OpenClaw's global fetch interceptor mutating the init.headers object by injecting a hidden Symbol (Symbol(sensitiveHeaders)). In Node.js 22, the native undici fetch engine strictly validates the Headers initialization object and immediately throws a TypeError if it encounters any non-string Symbol keys.

ERROR LOG:

[plugins] Plugin init error: Headers constructor: Key Symbol(sensitiveHeaders) in init is a symbol, which cannot be converted to a ByteString.

ROOT CAUSE ANALYSIS

  1. discord.js relies on Node's native fetch (undici).

  2. When making an API request, discord.js creates a standard JavaScript object for headers (e.g., { Authorization: "Bot ..." }).

  3. OpenClaw intercepts this fetch call globally and attaches Symbol(sensitiveHeaders) to the headers object (likely for security/tracing).

  4. Node 22's undici engine passes this modified object into new Headers(init).

  5. The Headers constructor iterates over the keys, hits the OpenClaw-injected Symbol, and throws the ByteString conversion error.

CURRENT WORKAROUND

Plugin developers currently have to completely abandon discord.js and write custom polling wrappers using node:https to bypass the OpenClaw fetch interceptor entirely.

SUGGESTED FIXES.

OpenClaw's fetch interceptor should avoid injecting raw Symbols directly into the init.headers dictionary that is passed down to native fetch. If tracing/tracking is required, consider wrapping the fetch promise or attaching the metadata to a different, non-iterable scope that doesn't conflict with undici's strict prototype validation.

MY ENVIRONMENT

-> OS: WSL2 / Ubuntu (Windows) -> Node.js Version: v22.x -> OpenClaw Version: Latest (2026.5.x) -> Plugin Dependencies: discord.js@^14.14.1

<img width="1449" height="68" alt="Image" src="https://github.com/user-attachments/assets/25506082-faca-48c4-a9cf-7799c4182da4" />

Steps to reproduce

  1. Run OpenClaw on Node.js 22.

2.Create a basic OpenClaw plugin and install [email protected].

  1. Attempt to initialize the client:
import { Client, GatewayIntentBits } from "discord.js";

export default definePluginEntry({
  id: "discord_test",
  register(api) {
    const client = new Client({ intents: [GatewayIntentBits.Guilds] });
    // Crashes here during the internal fetch call
    client.login("BOT_TOKEN_HERE").catch(console.error);
  }
});

Expected behavior

When calling client.login() via discord.js inside an OpenClaw plugin, the client should successfully authenticate with the Discord API and establish a WebSocket connection without any internal fetch errors. The global OpenClaw environment should not interfere with standard third-party libraries utilizing native Node.js fetch.

Actual behavior

The OpenClaw gateway's global fetch interceptor taints the init.headers object by injecting a Symbol(sensitiveHeaders). When discord.js's internal undici engine processes this modified headers object on Node.js 22, it immediately crashes with a TypeError complaining about a Symbol that cannot be converted to a ByteString, causing the plugin initialization to fail completely.

OpenClaw version

2026.5.4

Operating system

WSL version: 2.6.3.0(WSL2) Ubuntu

Install method

pnpm dev

Model

google/gemma-31b-it

Provider / routing chain

no

Additional provider/model setup details

No response

Logs, screenshots, and evidence

<img width="1449" height="68" alt="Image" src="https://github.com/user-attachments/assets/25506082-faca-48c4-a9cf-7799c4182da4" />

Impact and severity

Affected : Users who use my plugin Severity : Critical

Additional information

No response

extent analysis

TL;DR

The most likely fix is to modify OpenClaw's fetch interceptor to avoid injecting raw Symbols directly into the init.headers dictionary.

Guidance

  • Identify the part of OpenClaw's code that injects Symbol(sensitiveHeaders) into the init.headers object and modify it to use a different approach for tracing or security purposes.
  • Consider wrapping the fetch promise or attaching metadata to a non-iterable scope to avoid conflicts with undici's strict prototype validation.
  • Verify that the modified OpenClaw fetch interceptor does not interfere with discord.js's internal fetch calls by testing the plugin with the updated code.
  • If the issue persists, try to isolate the problem by creating a minimal reproducible example that demonstrates the conflict between OpenClaw's fetch interceptor and discord.js.

Example

// Modified OpenClaw fetch interceptor
const originalFetch = global.fetch;
global.fetch = function fetch(...args) {
  // Avoid injecting raw Symbols into the init.headers dictionary
  const headers = args[1] && args[1].headers;
  if (headers && headers[Symbol('sensitiveHeaders')]) {
    delete headers[Symbol('sensitiveHeaders')];
  }
  return originalFetch(...args);
};

Notes

This solution assumes that the issue is caused by the injection of raw Symbols into the init.headers dictionary. If the problem is more complex, additional debugging and testing may be required.

Recommendation

Apply the workaround by modifying OpenClaw's fetch interceptor to avoid injecting raw Symbols into the init.headers dictionary, as this is the most likely cause of the issue.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

When calling client.login() via discord.js inside an OpenClaw plugin, the client should successfully authenticate with the Discord API and establish a WebSocket connection without any internal fetch errors. The global OpenClaw environment should not interfere with standard third-party libraries utilizing native Node.js fetch.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: Global fetch interceptor injects Symbol(sensitiveHeaders), breaking discord.js (undici) on Node.js 22 [2 pull requests, 1 comments, 2 participants]