openclaw - ✅(Solved) Fix [Bug]: sessions_spawn rejects plugin channels (feishu, wecom, etc.) with 'unknown channel' [2 pull requests, 1 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#59181Fetched 2026-04-08 02:27:46
View on GitHub
Comments
0
Participants
1
Timeline
3
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×2referenced ×1

sessions_spawn fails with "invalid agent params: unknown channel: feishu" (or wecom, lightclawbot, etc.) when called from a session running on a plugin-provided channel, even though the channel is fully functional for message sending/receiving.

Error Message

  1. Observe error: "invalid agent params: unknown channel: feishu"

Root Cause

In gateway-cli-DlnlX7IW.js:9677-9682, the spawn handler validates channel hints:

const isKnownGatewayChannel = (value) => isGatewayMessageChannel(value);
const channelHints = [request.channel, request.replyChannel]...
for (const rawChannel of channelHints) {
    const normalized = normalizeMessageChannel(rawChannel);
    if (normalized && normalized !== "last" && !isKnownGatewayChannel(normalized)) {
        respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST,
            `invalid agent params: unknown channel: ${String(normalized)}`));
        return;
    }
}

isGatewayMessageChannel() checks listGatewayMessageChannels() which returns [...CHANNEL_IDS, ...listPluginChannelIds()].

  • CHANNEL_IDS is hardcoded: ["telegram", "whatsapp", "discord", "irc", "googlechat", "slack", "signal", "imessage", "line"]
  • listPluginChannelIds() calls listRegisteredChannelPluginIds() which queries the active plugin channel registry

Plugin channels like feishu register as transport plugins (WebSocket/webhook for message I/O) and register tools (feishu_doc, feishu_chat, etc.), but they apparently do not register themselves in the channel plugin registry that listRegisteredChannelPluginIds() queries.

This creates a split-brain state:

  • ✅ Feishu channel is running, sending/receiving messages normally
  • ✅ Feishu tools are registered and functional
  • ❌ Feishu is NOT in the channel plugin registry
  • sessions_spawn rejects feishu as "unknown channel"

PR fix notes

PR #61361: fix: use pinned channel registry for channel plugin validation

Description (problem / solution / changelog)

Summary

Fixes #61358

in src/channels/registry.ts reads from the mutable getActivePluginRegistry(), which can temporarily return an empty channel list during plugin reload cycles. This causes sessions_spawn to intermittently fail with unknown channel: <plugin-id> for all third-party channel plugins (openclaw-weixin, qqbot, etc.).

Root Cause

The plugin system already has a pinned channel surface mechanism (getActivePluginChannelRegistry()) designed to keep channel plugins stable after gateway startup. However, the channel validation chain does not use it:

isGatewayMessageChannel() → listGatewayMessageChannels() → listPluginChannelIds()
  → listRegisteredChannelPluginEntries() → getActivePluginRegistry()  ❌ mutable

Bundled channels (telegram, discord, etc.) are unaffected because they are in the hardcoded CHANNEL_IDS array and never hit the plugin registry path.

Fix

Change listRegisteredChannelPluginEntries() to prefer the pinned channel registry:

// Before
function listRegisteredChannelPluginEntries() {
  return getActivePluginRegistry()?.channels ?? [];
}

// After
function listRegisteredChannelPluginEntries() {
  const pinned = getActivePluginChannelRegistry();
  if (pinned && pinned.channels && pinned.channels.length > 0) {
    return pinned.channels;
  }
  return getActivePluginRegistry()?.channels ?? [];
}

Testing

  • Verified against OpenClaw 2026.4.2 source code
  • The pinned registry is populated during reloadDeferredGatewayPlugins() which runs after startup
  • Fallback to mutable registry ensures backward compatibility

Affected

  • Third-party channel plugins: openclaw-weixin, qqbot, and any non-bundled channel
  • No impact on bundled channels (telegram, discord, whatsapp, etc.)

Changed files

  • src/channels/registry.ts (modified, +18/-1)

PR #61366: fix: resolve intermittent 'unknown channel' errors for plugin channels in sessions_spawn

Description (problem / solution / changelog)

Summary

Fixes #61358 Closes #59181 (supersedes the suggested fixes there) Related: #48790, #55338

Problem

intermittently fails with for all third-party channel plugins (openclaw-weixin, qqbot, feishu, wecom, lightclawbot, etc.). This has two root causes:

Root Cause 1: Mutable registry swap (#61358, #48790)

reads from the mutable , which can be temporarily empty during plugin reload cycles. Bundled channels (telegram, discord, etc.) are unaffected because they are hardcoded in .

Root Cause 2: Split-brain registration (#59181)

Plugin channels may not be registered in the channel plugin registry at all, even though they are fully functional for message sending/receiving. The channel field in a spawn request comes from the parent session and is metadata-only — the subagent does not communicate through the channel directly.

Changes

1. (primary fix)

Skip strict channel validation for subagent spawn requests (). The channel is only used as metadata for routing announcement results, not for actual channel communication.

Non-spawn requests (chat.send, direct agent calls, etc.) still receive strict channel validation.

2. (defense-in-depth)

Use the pinned channel registry () as the primary source in , falling back to the mutable active registry. This prevents registry swap from affecting all callers of the channel plugin list.

Why this is safe

  • Subagent spawns communicate entirely through the internal spawn mechanism (task input → agent execution → announcement message)
  • The channel field is metadata for routing the announcement back to the requester session
  • If the channel is truly invalid, the announcement routing will gracefully degrade (no delivery), but the spawn itself succeeds
  • Non-spawn agent calls still validate channels strictly

Testing

  • Verified against OpenClaw 2026.4.2 source code
  • The combination is only set by in
  • Regular agent calls via chat.send always have or no lane

Changed files

  • src/channels/registry.ts (modified, +18/-1)
  • src/gateway/server-methods/agent.ts (modified, +12/-0)

Code Example

const isKnownGatewayChannel = (value) => isGatewayMessageChannel(value);
const channelHints = [request.channel, request.replyChannel]...
for (const rawChannel of channelHints) {
    const normalized = normalizeMessageChannel(rawChannel);
    if (normalized && normalized !== "last" && !isKnownGatewayChannel(normalized)) {
        respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST,
            `invalid agent params: unknown channel: ${String(normalized)}`));
        return;
    }
}
RAW_BUFFERClick to expand / collapse

Summary

sessions_spawn fails with "invalid agent params: unknown channel: feishu" (or wecom, lightclawbot, etc.) when called from a session running on a plugin-provided channel, even though the channel is fully functional for message sending/receiving.

Environment

  • OpenClaw version: 2026.3.28
  • OS: Linux 6.8.0-71-generic (x64)
  • Node: v22.22.1
  • Affected channels: feishu, wecom, lightclawbot, openclaw-weixin (all plugin-provided channels)
  • Working channels: telegram, discord, etc. (built-in channels in CHAT_CHANNEL_ORDER)

Root Cause

In gateway-cli-DlnlX7IW.js:9677-9682, the spawn handler validates channel hints:

const isKnownGatewayChannel = (value) => isGatewayMessageChannel(value);
const channelHints = [request.channel, request.replyChannel]...
for (const rawChannel of channelHints) {
    const normalized = normalizeMessageChannel(rawChannel);
    if (normalized && normalized !== "last" && !isKnownGatewayChannel(normalized)) {
        respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST,
            `invalid agent params: unknown channel: ${String(normalized)}`));
        return;
    }
}

isGatewayMessageChannel() checks listGatewayMessageChannels() which returns [...CHANNEL_IDS, ...listPluginChannelIds()].

  • CHANNEL_IDS is hardcoded: ["telegram", "whatsapp", "discord", "irc", "googlechat", "slack", "signal", "imessage", "line"]
  • listPluginChannelIds() calls listRegisteredChannelPluginIds() which queries the active plugin channel registry

Plugin channels like feishu register as transport plugins (WebSocket/webhook for message I/O) and register tools (feishu_doc, feishu_chat, etc.), but they apparently do not register themselves in the channel plugin registry that listRegisteredChannelPluginIds() queries.

This creates a split-brain state:

  • ✅ Feishu channel is running, sending/receiving messages normally
  • ✅ Feishu tools are registered and functional
  • ❌ Feishu is NOT in the channel plugin registry
  • sessions_spawn rejects feishu as "unknown channel"

Why This Matters

The channel field in the spawn request comes from the parent session row (sessionRow.channel), populated automatically by the gateway. The spawned subagent does not actually need to communicate through this channel — it receives a task via the spawn mechanism and returns results via sessions_send. The channel is metadata context, not a functional requirement for the subagent.

This means any agent running on a plugin channel (main agent on feishu, wecom-work agent on wecom, etc.) cannot use sessions_spawn to delegate to other agents, even though the spawn is a purely internal agent-to-agent operation that does not involve external channel communication.

Impact

  • All plugin-provided channels (feishu, wecom, lightclawbot, openclaw-weixin, yuanbao, qqbot, adp-openclaw, ddingtalk) are affected
  • Multi-agent architectures using these channels cannot spawn subagents
  • Only agents running on the 9 built-in Western IM channels can spawn subagents
  • This blocks Chinese market channel users from using the multi-agent feature

Steps to Reproduce

  1. Configure feishu channel in openclaw.json
  2. Configure a second agent (e.g. "coder") in agents config
  3. Send a message to the feishu bot
  4. Main agent calls sessions_spawn({ agentId: "coder", task: "..." })
  5. Observe error: "invalid agent params: unknown channel: feishu"

Suggested Fix

Option A: Register plugin channels in the channel plugin registry at startup, not just the transport layer.

Option B: Skip channel validation for sessions_spawn when the channel hint matches the current session context. The subagent does not need to communicate through the channel directly.

Option C: Allow sessions_spawn to omit channel context entirely for internal agent-to-agent spawns that do not require delivery routing.

Related Issues

  • #48790 — Channel plugin registrations lost on runtime registry swap
  • #55338 — Outbound message "Unknown channel" when registry is partial
  • #49129 — Cron delivery silently fails for plugin-provided channels
  • #25775 — Custom plugin channel config rejected despite plugin loaded
  • #56303 — sessions_spawn hardcodes channel names instead of using plugin metadata

extent analysis

TL;DR

The most likely fix is to modify the sessions_spawn validation to skip checking the channel hint when it matches the current session context, allowing plugin-provided channels to spawn subagents.

Guidance

  • Review the isKnownGatewayChannel function to understand how it validates channel hints and consider modifying it to accommodate plugin-provided channels.
  • Investigate Option B from the suggested fixes, which involves skipping channel validation for sessions_spawn when the channel hint matches the current session context.
  • Consider registering plugin channels in the channel plugin registry at startup, as suggested in Option A, to ensure consistency in channel registration.
  • Evaluate the impact of allowing sessions_spawn to omit channel context entirely for internal agent-to-agent spawns, as proposed in Option C.

Example

// Modified validation logic to skip checking channel hint when it matches the current session context
if (normalized && normalized !== "last" && request.channel === sessionRow.channel) {
    // Skip validation for matching channel hints
} else if (!isKnownGatewayChannel(normalized)) {
    respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST,
        `invalid agent params: unknown channel: ${String(normalized)}`));
    return;
}

Notes

The provided code snippet and suggested fixes imply that the issue lies in the validation logic of the sessions_spawn function. However, the root cause may be more complex, and additional investigation may be necessary to ensure a comprehensive solution.

Recommendation

Apply workaround by modifying the sessions_spawn validation logic to skip checking the channel hint when it matches the current session context, as this approach seems to be the most straightforward and least invasive solution.

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…

Still need to ship something?

×6

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

Back to top recommendations

TRENDING