openclaw - ✅(Solved) Fix Discord thread-bound subagent sessions do not exclusively own the thread across multiple bots [1 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#49373Fetched 2026-04-08 00:55:54
View on GitHub
Comments
1
Participants
2
Timeline
2
Reactions
0
Participants
Timeline (top)
commented ×1cross-referenced ×1

When sessions_spawn({ agentId: "soren", thread: true, mode: "session" }) creates a Discord thread-bound subagent session, follow-up messages in that thread can still be picked up by another Discord bot's normal channel routing instead of continuing to route to the bound subagent session.

This results in a rogue fallback session such as:

agent:soren:discord:channel:<threadId>

instead of continuing the existing bound subagent session:

agent:soren:subagent:<uuid>

Root Cause

When sessions_spawn({ agentId: "soren", thread: true, mode: "session" }) creates a Discord thread-bound subagent session, follow-up messages in that thread can still be picked up by another Discord bot's normal channel routing instead of continuing to route to the bound subagent session.

This results in a rogue fallback session such as:

agent:soren:discord:channel:<threadId>

instead of continuing the existing bound subagent session:

agent:soren:subagent:<uuid>

Fix Action

Fix / Workaround

  1. Add a cross-account Discord thread-binding lookup by threadId.
  2. In Discord preflight, if the current account has no local binding but another Discord account already owns the thread, suppress normal dispatch on the non-owning bot.
  3. Keep the existing same-account bound-session routing behavior.

PR fix notes

PR #49434: fix(discord): preserve bound thread isolation across bot accounts

Description (problem / solution / changelog)

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem: In multi-bot Discord setups, a thread created for sessions_spawn(thread=true, mode="session") could still be picked up by another bot account's general Discord routing instead of staying attached to the active bound subagent session.
  • Why it matters: This breaks thread/session isolation and can cause follow-up messages to escape the intended session scope, producing replies from the wrong bot/session context.
  • What changed: Discord preflight now suppresses generic routing when another Discord account already owns an active thread binding, using the current preflight config to ignore stale or removed-account bindings.
  • What did NOT change (scope boundary): This does not add shared-thread routing, change same-account binding behavior, or introduce new config flags.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

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

Linked Issue/PR

  • Closes #49373
  • Related #

User-visible / Behavior Changes

  • Follow-up messages in a Discord thread bound to an active subagent session are no longer allowed to fall through to another bot account's general channel routing.
  • Removed or stale bindings for non-running / non-configured Discord accounts no longer suppress valid follow-up messages.

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: Ubuntu
  • Runtime/container: local OpenClaw dev checkout
  • Model/provider: N/A
  • Integration/channel (if any): Discord
  • Relevant config (redacted): multi-account Discord setup with thread bindings enabled for bound subagent sessions

Steps

  1. Create a Discord thread via sessions_spawn(agentId="soren", thread=true, mode="session") from one bot/account.
  2. Ensure the thread is bound to the spawned subagent session.
  3. Send a follow-up message in that same Discord thread that is also visible to another configured Discord bot/account.

Expected

  • The follow-up routes only to the active bound subagent session that owns the thread.

Actual

  • Before this change, another bot/account could miss the binding and create or use a generic Discord channel session for the same thread.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: added/ran focused regressions for cross-account thread ownership suppression, stale foreign binding ignore, root-thread-binding stale config ignore, and config-snapshot mismatch handling.
  • Edge cases checked: foreign manager stopped but stale binding record remains; root Discord threadBindings enabled without active foreign account; explicit preflight config differs from runtime snapshot.
  • What you did not verify: live Discord multi-bot end-to-end behavior in a running guild; full repo pnpm test is not green on this checkout due unrelated existing failures; codex review --uncommitted could not complete because of transport disconnects.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps:

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: revert this PR or temporarily disable Discord thread bindings for the affected account(s).
  • Files/config to restore: src/discord/monitor/message-handler.preflight.ts, src/discord/monitor/thread-bindings.manager.ts, src/discord/monitor/thread-bindings.ts, src/discord/monitor/message-handler.preflight.test.ts
  • Known bad symptoms reviewers should watch for: valid follow-up messages in bound Discord threads being dropped unexpectedly, especially in multi-account setups.

Risks and Mitigations

  • Risk: foreign-owner suppression could incorrectly drop messages if stale bindings are treated as active owners.

    • Mitigation: suppression ignores stale bindings for removed/non-configured accounts and uses the active preflight config instead of global runtime snapshot state.
  • Risk: multi-bot/shared-thread workflows may expect non-owning bots to continue responding in the same thread.

    • Mitigation: this PR intentionally preserves exclusive ownership semantics only for active bound-session threads and does not change unbound-thread behavior.

AI-assisted. Lightly tested locally with focused Discord regression tests and manual diff review.

Changed files

  • extensions/discord/src/monitor/message-handler.preflight.test.ts (modified, +303/-0)
  • extensions/discord/src/monitor/message-handler.preflight.ts (modified, +17/-1)
  • extensions/discord/src/monitor/thread-bindings.manager.ts (modified, +77/-0)
  • extensions/discord/src/monitor/thread-bindings.ts (modified, +1/-0)
RAW_BUFFERClick to expand / collapse

Summary

When sessions_spawn({ agentId: "soren", thread: true, mode: "session" }) creates a Discord thread-bound subagent session, follow-up messages in that thread can still be picked up by another Discord bot's normal channel routing instead of continuing to route to the bound subagent session.

This results in a rogue fallback session such as:

agent:soren:discord:channel:<threadId>

instead of continuing the existing bound subagent session:

agent:soren:subagent:<uuid>

Expected

Once a subagent session is thread-bound in mode="session", that thread should remain attached to that subagent session until it is explicitly released, unfocused, killed, or expires.

Primary/general channel routing should not be allowed to reclaim that thread while the binding is active.

Actual

In a multi-bot Discord setup:

  1. Bot A creates the thread-bound subagent session successfully.
  2. The bound subagent completes its initial task and posts back correctly.
  3. A user posts a follow-up message in the same thread.
  4. Bot B, which also sees the thread message, does not resolve the existing binding and falls back to its normal channel routing.
  5. A new generic session is created with no task context, producing an incorrect reply.

Why this happens

Discord thread binding lookup is effectively account-scoped:

  • the Discord subagent spawning hook binds using the requester's Discord accountId
  • session binding adapters are registered by channel + accountId
  • inbound Discord preflight only resolves bindings through the current bot account's adapter

So if the binding was created under one Discord bot account, another Discord bot account receiving the same thread message cannot see it and falls back to standard route resolution.

Within a single bot account, bound-thread precedence appears correct. The failure happens when multiple Discord bot accounts can observe the same thread.

Impact

This breaks the expected invariant for persistent thread-bound subagent sessions:

  • the primary session owns the broader channel
  • the bound subagent should own the focused thread

Today, the broader channel routing can leak back into the focused thread when another bot handles the same inbound message.

Suggested fix

Treat an active Discord thread binding as an exclusive thread claim by default.

Specifically:

  1. Add a cross-account Discord thread-binding lookup by threadId.
  2. In Discord preflight, if the current account has no local binding but another Discord account already owns the thread, suppress normal dispatch on the non-owning bot.
  3. Keep the existing same-account bound-session routing behavior.

This would preserve the current model while fixing the multi-bot leakage bug without requiring a broader agent-to-bot affinity redesign.

Optional future extension

If OpenClaw wants to support explicit shared / multi-bot thread attachment later, that should likely be an opt-in routing mode. The safe default for mode="session" should remain exclusive ownership of the focused thread while the binding is active.

Repro

  1. Run two Discord bot accounts that can both receive messages from the same thread.

  2. From bot A's conversation, call:

    sessions_spawn({ agentId: "soren", thread: true, mode: "session" })

  3. Let OpenClaw create a thread and bind:

    agent:soren:subagent:<uuid>

  4. Post a follow-up message in that thread.

  5. Observe bot B create a generic session like:

    agent:soren:discord:channel:<threadId>

instead of continuing the bound subagent session.

Relevant source areas

  • src/discord/monitor/message-handler.preflight.ts
  • src/discord/monitor/thread-bindings.manager.ts
  • src/discord/monitor/thread-bindings.lifecycle.ts
  • src/infra/outbound/session-binding-service.ts
  • extensions/discord/src/subagent-hooks.ts
  • src/agents/subagent-registry.ts

extent analysis

Fix Plan

To address the issue of multiple Discord bot accounts interfering with each other's thread-bound subagent sessions, we need to implement a cross-account Discord thread-binding lookup and modify the preflight logic. Here are the steps:

  1. Add cross-account Discord thread-binding lookup:

    • Modify src/discord/monitor/thread-bindings.manager.ts to store thread bindings in a centralized store (e.g., Redis or a database) with the threadId as the key.
    • Update src/infra/outbound/session-binding-service.ts to query this centralized store for thread bindings.
  2. Modify Discord preflight logic:

    • In src/discord/monitor/message-handler.preflight.ts, check if the current account has no local binding but another Discord account already owns the thread.
    • If so, suppress normal dispatch on the non-owning bot by returning early or throwing an exception.

Example code snippet for the modified preflight logic:

// src/discord/monitor/message-handler.preflight.ts
import { getThreadBinding } from './thread-bindings.manager';

const handlePreflight = async (message) => {
  const threadBinding = await getThreadBinding(message.threadId);
  if (threadBinding && threadBinding.accountId !== message.accountId) {
    // Suppress normal dispatch on non-owning bot
    return { skipDispatch: true };
  }
  // Existing logic for same-account bound-session routing
};
  1. Update thread binding adapters:
    • Modify src/discord/monitor/thread-bindings.lifecycle.ts to register thread binding adapters with the centralized store.

Example code snippet for registering thread binding adapters:

// src/discord/monitor/thread-bindings.lifecycle.ts
import { registerThreadBinding } from './thread-bindings.manager';

const registerAdapter = async (threadId, accountId) => {
  await registerThreadBinding(threadId, accountId);
};

Verification

To verify the fix, follow the repro steps and observe that the follow-up message in the thread is correctly routed to the bound subagent session instead of creating a new generic session.

Extra Tips

  • Ensure proper error handling and logging in the modified code to handle cases where the centralized store is unavailable or the thread binding is not found.
  • Consider implementing a timeout or expiration mechanism for thread bindings to prevent stale bindings from interfering with new sessions.

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

openclaw - ✅(Solved) Fix Discord thread-bound subagent sessions do not exclusively own the thread across multiple bots [1 pull requests, 1 comments, 2 participants]