-
-
Notifications
You must be signed in to change notification settings - Fork 52.5k
Description
name: Bug report
about: Report a problem or unexpected behavior in Clawdbot.
title: "[Bug]: Session key inconsistency causes duplicate sessions and missing messages in TUI/WebUI"
labels: bug
Summary
There is an inconsistency in how recordInboundSession and initSessionState handle sessionKey, causing duplicate session entries to be created when plugins pass mixed-case session keys. This results in user messages being written to the wrong transcript file and not appearing in TUI/WebUI, even though AI replies are correctly generated and sent.
Steps to reproduce
- Create a channel plugin that calls
recordInboundSessionwith a mixed-casesessionKey(e.g.,agent:main:wechat:miniprogram:onslD1wi_zoYBJggvREAPv-Dtl8E) - Send a message through the plugin
- Check
sessions.json- you will see multiple session entries for the same user (one with original case, one with lowercase) - Check TUI/WebUI - user messages are not displayed, but AI replies are visible
Expected behavior
- Only one session entry should be created per user
- User messages should appear in TUI/WebUI alongside AI replies
- Session keys should be consistently normalized (lowercase) throughout the codebase
Actual behavior
- Multiple session entries are created for the same user (differentiated by case)
- User messages are written to a transcript file that TUI/WebUI doesn't display
- AI replies work correctly but user messages are missing from the UI
Environment
- Clawdbot version: 2026.2.3 (5d82c82)
- OS: macOS 26.2 (arm64)
- Install method: npm/pnpm
Root Cause Analysis
The Problem
-
recordInboundSession(insrc/channels/session.ts) uses the providedsessionKeyparameter directly without normalization:export async function recordInboundSession(params: { storePath: string; sessionKey: string; // Uses the provided sessionKey directly, no normalization ctx: MsgContext; // ... }): Promise<void> { const { storePath, sessionKey, ctx, groupResolution, createIfMissing } = params; void recordSessionMetaFromInbound({ storePath, sessionKey, // Used directly, does not call resolveSessionKey ctx, // ... }).catch(params.onRecordError); }
-
initSessionState(insrc/auto-reply/reply/session.ts) callsresolveSessionKeywhich normalizes the key to lowercase:sessionKey = resolveSessionKey(sessionScope, sessionCtxForState, mainKey);
-
resolveSessionKey(insrc/config/sessions/session-key.ts) convertsctx.SessionKeyto lowercase:export function resolveSessionKey(scope: SessionScope, ctx: MsgContext, mainKey?: string) { const explicit = ctx.SessionKey?.trim(); if (explicit) { return explicit.toLowerCase(); // ⚠️ Converts to lowercase } // Otherwise regenerates based on scope and ctx.From const raw = deriveSessionKey(scope, ctx); // ... }
Impact
- If a plugin passes
agent:main:wechat:miniprogram:onslD1wi_zoYBJggvREAPv-Dtl8E(mixed case) recordInboundSessioncreates a session entry with this keyinitSessionStateconverts it toagent:main:wechat:miniprogram:onsld1wi_zoybjggvreapv-dtl8e(lowercase)- Result: Two different session entries, messages split between them
Proposed Fixes
Solution 1: Normalize sessionKey in recordInboundSession
Modify src/channels/session.ts:
import { resolveSessionKey } from "../config/sessions/session-key.js";
export async function recordInboundSession(params: {
storePath: string;
sessionKey: string;
ctx: MsgContext;
// ...
}): Promise<void> {
const { storePath, sessionKey, ctx, groupResolution, createIfMissing } = params;
// Normalize sessionKey to ensure consistency with initSessionState
const normalizedSessionKey = ctx.SessionKey?.trim()
? ctx.SessionKey.trim().toLowerCase()
: sessionKey.toLowerCase();
void recordSessionMetaFromInbound({
storePath,
sessionKey: normalizedSessionKey, // Use normalized key
ctx,
groupResolution,
createIfMissing,
}).catch(params.onRecordError);
// ...
}Solution 2: Ensure plugins always pass lowercase SessionKey
In plugin code, ensure SessionKey is always lowercase (workaround, not a fix):
const msgContext = runtime.channel.reply.finalizeInboundContext({
// ...
SessionKey: sessionKey.toLowerCase(), // Ensure lowercase
// ...
});Solution 3: Normalize in recordSessionMetaFromInbound (Recommended)
Modify src/config/sessions/store.ts:
export async function recordSessionMetaFromInbound(params: {
storePath: string;
sessionKey: string;
ctx: MsgContext;
// ...
}): Promise<SessionEntry | null> {
const { storePath, sessionKey, ctx } = params;
const createIfMissing = params.createIfMissing ?? true;
// Normalize sessionKey (convert to lowercase)
const normalizedKey = sessionKey.toLowerCase();
return await updateSessionStore(storePath, (store) => {
const existing = store[normalizedKey]; // Use normalized key
// ...
store[normalizedKey] = next; // Use normalized key
return next;
});
}Solution 3 is recommended because:
- Normalizes at the data storage layer, ensuring all session keys are lowercase
- No need to modify all call sites of
recordInboundSession - Consistent with
resolveSessionKeybehavior (both convert to lowercase)
Affected Files
src/channels/session.ts-recordInboundSessionfunctionsrc/config/sessions/store.ts-recordSessionMetaFromInboundfunctionsrc/config/sessions/session-key.ts-resolveSessionKeyfunctionsrc/auto-reply/reply/session.ts-initSessionStatefunction
Logs or screenshots
Example log output showing the issue:
2026-02-05T10:00:54.429Z info gateway/channels/wechat-miniprogram
Route resolved: agentId=main, sessionKey=agent:main:main, mainSessionKey=agent:main:main
2026-02-05T10:00:54.430Z info gateway/channels/wechat-miniprogram
Recording inbound session: sessionKey=agent:main:wechat:miniprogram:onslD1wi_zoYBJggvREAPv-Dtl8E
Notice the mismatch: resolveAgentRoute returns agent:main:main, but recordInboundSession is called with agent:main:wechat:miniprogram:onslD1wi_zoYBJggvREAPv-Dtl8E.
Multiple sessions in openclaw status:
Sessions
┌─────────────────────────────────────────────┬────────┬─────────┬──────────────┬────────────────┐
│ Key │ Kind │ Age │ Model │ Tokens │
├─────────────────────────────────────────────┼────────┼─────────┼──────────────┼────────────────┤
│ agent:main:wechat:miniprogram:o… │ direct │ 2m ago │ glm-4.7 │ 14k/205k (7%) │
│ agent:main:main │ direct │ 2m ago │ glm-4.7 │ 26k/205k (13%) │
│ agent:main:wechat:miniprogram:o… │ direct │ 2m ago │ glm-4.7 │ 0.0k/205k (0%) │
└─────────────────────────────────────────────┴────────┴─────────┴──────────────┴────────────────┘
Workaround
Manually delete duplicate session entries from ~/.openclaw/agents/main/sessions/sessions.json. After cleanup, TUI/WebUI will display correctly.
Testing Recommendations
- Call
recordInboundSessionwith a mixed-casesessionKey - Verify only one session entry is created in
sessions.json(lowercase) - Verify user messages are written to the correct transcript file
- Verify TUI/WebUI correctly displays messages