Skip to content

Session origin retains stale per-channel fields (nativeChannelId, threadId) across a channel switch in a dmScope:"main" session #95325

Description

@gorkem2020

Summary

With session.dmScope: "main", a user's DMs to an agent across channels (Slack, Telegram, webchat) share one session. On a channel switch (for example Slack to Telegram), the session origin's per-channel identity fields are not reset. mergeOrigin only overwrites a field when the new inbound supplies it; Telegram DMs supply no nativeChannelId (or threadId), so the previous channel's Slack channel id persists in a now-Telegram session, and keeps persisting on every subsequent Telegram turn until the user messages on the original channel again.

Reproduction (deterministic, verified on two separate agents)

  1. Message an agent in a Slack DM (Slack channel id like Dxxxxxxxx).
  2. As the same user, message that agent on Telegram (same dmScope:"main" session).
  3. Inspect the session origin: provider, surface, from, to, and accountId correctly become Telegram, but origin.nativeChannelId still holds the Slack channel id.

It does not clear on subsequent Telegram turns. It is re-stamped only when the user later sends a message on the original (Slack) channel, or on a session reset.

Root cause

mergeOrigin merges field by field, overwriting only when the new value is present:

const merged = existing ? { ...existing } : {};
if (next?.provider) merged.provider = next.provider;                      // updates
if (next?.nativeChannelId) merged.nativeChannelId = next.nativeChannelId; // only if supplied
if (next?.threadId != null && next.threadId !== "") merged.threadId = next.threadId;

Channels that do not carry a native channel id (Telegram DMs) leave the previous channel's value in place, and nothing resets it when provider or surface changes.

Impact

Message delivery is unaffected (route.target.to updates correctly). But native-channel-keyed operations (reactions, native threading, native message references) and any status or inspection that reads origin.nativeChannelId will reference the previous channel for the entire duration of the new-channel session. For example, an agent on Telegram reports the prior Slack account and channel when asked about its current context.

Suggested fix

When provider (or surface) differs from the existing origin, reset the channel-specific fields (nativeChannelId, nativeDirectUserId, threadId) rather than preserving them, treating a provider change as a fresh channel identity.

Environment

OpenClaw 2026.6.1, Linux, Node 24. session.scope: per-sender, session.dmScope: main.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    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