openclaw - 💡(How to fix) Fix Beta blocker: runtime policy session key leaks into LCM context for Telegram DMs

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…

Direct Telegram DMs can resolve a per-peer runtimePolicySessionKey and then use that policy key as the Lossless/LCM context-engine sessionKey. When the configured/default user-facing session is the canonical main lane (agent:main:main), this breaks session continuity, can select stale per-DM LCM conversations, and can produce both a full-context failure fallback and a later normal reply for one inbound message.

This is distinct from #84885 (partial preview spam), #84886 (Telegram polling dispatch idempotency), and #84887 (runtime LLM allowlist diagnostic double-prefixing).

Error Message

H --> I[Generic Telegram error fallback]

Root Cause

  • one inbound Telegram message to produce both a failure fallback and an agent-authored reply,
  • full-context gpt-5.5 requests from stale history selection,
  • sudden API/token burn,
  • broken expectation that the agent-name main session remains the single continuity lane,
  • confusing LCM compaction behavior because the wrong active conversation is selected.

Fix Action

Fix / Workaround

This is distinct from #84885 (partial preview spam), #84886 (Telegram polling dispatch idempotency), and #84887 (runtime LLM allowlist diagnostic double-prefixing).

Lossless-Claw was verified as the vanilla latest npm package, not a local checkout or branched patch:

Code Example

sessionKey=agent:main:main

---

2026-05-21T18:28:02.266+07:00 Inbound message telegram:<redacted-peer> -> @EvaLabsBot (direct, 4 chars)

2026-05-21T18:28:03.428+07:00 [lcm] bootstrap: session file shrank past checkpoint conversation=1876 session=boot-2026-05-21_07-53-21-505-412ec8bc sessionKey=agent:main:telegram:default:direct:<redacted-peer> checkpointOffset=1897994 currentSize=179112

2026-05-21T18:28:50.843+07:00 [lcm] assemble: done conversation=1876 session=boot-2026-05-21_07-53-21-505-412ec8bc sessionKey=agent:main:telegram:default:direct:<redacted-peer> contextItems=416 summaryContextItems=17 inputMessages=124 outputMessages=417 tokenBudget=258000 estimatedTokens=227240

2026-05-21T18:28:50.888+07:00 codex app-server context-engine projection decision sessionKey=agent:main:telegram:default:direct:<redacted-peer> previousEpoch=summary-prefix-v1:1872:... reason=context-engine-binding-mismatch assembledMessages=417 projectedPromptChars=817231

2026-05-21T18:29:12.721+07:00 embedded run failover decision provider=openai-codex model=gpt-5.5 rawErrorPreview="Codex ran out of room in the model's context window. Start a new thread or clear earlier history before retrying."

2026-05-21T18:29:24.073+07:00 telegram outbound send ok messageId=24348 operation=sendMessage deliveryKind=text

2026-05-21T18:29:22.697+07:00 [lcm] assemble: done conversation=1872 session=boot-2026-05-21_11-15-48-922-1e2fa501 sessionKey=agent:main:main contextItems=165 summaryContextItems=2 inputMessages=125 outputMessages=137 tokenBudget=258000 estimatedTokens=61135

2026-05-21T18:29:22.718+07:00 codex app-server context-engine projection decision sessionKey=agent:main:main previousEpoch=summary-prefix-v1:1876:... reason=context-engine-binding-mismatch assembledMessages=137 projectedPromptChars=166128

2026-05-21T18:29:33.958+07:00 telegram outbound send ok messageId=24349 operation=sendMessage deliveryKind=text
2026-05-21T18:29:33.965+07:00 res ok message.action channel=telegram

---

thread 019e4a4b-aab0-7c12-8bbd-1f5e13948992 model=gpt-5.5 tokens_used=258400 first_user_message_chars=855222
thread 019e4a4c-1e96-7321-9502-a41c02ae198b model=gpt-5.5 tokens_used=198484 first_user_message_chars=204297

---

/Users/lume/.openclaw/node_modules/@martian-engineering/lossless-claw version=0.11.2
/Users/lume/.openclaw/extensions/node_modules/@martian-engineering/lossless-claw version=0.11.2
/Users/lume/.openclaw/npm/node_modules/@martian-engineering/lossless-claw version=0.11.2

---

OpenClaw CLI/server version: 2026.5.19
Gateway pid: 87378
RPC: ok

---

session.dmScope: Config path not found
session.scope: Config path not found
session: { "reset": { "mode": "idle", "idleMinutes": 4320 } }
channels.telegram.direct.*.topics.*.agentId = "main"

---

/opt/homebrew/lib/node_modules/openclaw/dist/runtime-policy-session-key-0y7qYyqA.js
  resolveRuntimePolicySessionKey() returns buildAgentPeerSessionKey(... dmScope: "per-account-channel-peer") for direct chats when the canonical session key is a main-session alias.

/opt/homebrew/lib/node_modules/openclaw/dist/run-attempt-DI0_-QFr.js
  hookContext.sessionKey = sandboxSessionKey
  bootstrapHarnessContextEngine({ sessionKey: sandboxSessionKey, ... })
  buildCodexWorkspaceBootstrapContext({ sessionKey: sandboxSessionKey, ... })
  assembleHarnessContextEngine({ sessionKey: sandboxSessionKey, ... })

---

1872 | boot-2026-05-21_11-15-48-922-1e2fa501 | agent:main:main | active=1
1876 | boot-2026-05-21_07-53-21-505-412ec8bc | agent:main:telegram:default:direct:<redacted-peer> | active=1
1880 | boot-2026-05-05_11-44-39-074-95d65b06 | agent:main:telegram:default:direct:telegram:<redacted-peer> | active=1

---

{
  "dryRun": true,
  "beforeCount": 8,
  "afterCount": 7,
  "dmScopeRetired": 1,
  "wouldMutate": true
}

---

flowchart TD
  A[Telegram direct DM] --> B[Canonical route/session should be agent:main:main]
  B --> C[Runtime policy resolver derives per-peer policy key]
  C --> D[Policy key passed as sandboxSessionKey]
  D --> E[Context engine bootstrap/assemble uses sandboxSessionKey]
  E --> F[LCM selects stale per-DM conversation 1876]
  F --> G[Prompt projection grows to ~817k chars / full context]
  G --> H[Model fails before reply]
  H --> I[Generic Telegram error fallback]
  B --> J[Next projection uses main conversation 1872]
  J --> K[Agent sends visible reply via message.action]

  classDef bad fill:#ffd6d6,stroke:#cc3333,color:#111;
  class E,F,G,H,I bad;
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

Yes

Summary

Direct Telegram DMs can resolve a per-peer runtimePolicySessionKey and then use that policy key as the Lossless/LCM context-engine sessionKey. When the configured/default user-facing session is the canonical main lane (agent:main:main), this breaks session continuity, can select stale per-DM LCM conversations, and can produce both a full-context failure fallback and a later normal reply for one inbound message.

This is distinct from #84885 (partial preview spam), #84886 (Telegram polling dispatch idempotency), and #84887 (runtime LLM allowlist diagnostic double-prefixing).

Steps to reproduce

The local repro was an installed 2026.5.19 gateway with Telegram polling and the default/direct DM route bound to agent main.

  1. Use a Telegram DM route where the canonical conversation should stay attached to the agent main session.
  2. Have an older active Lossless conversation row for a per-DM key such as agent:main:telegram:default:direct:<peer-id>.
  3. Send a Telegram DM to the bot.
  4. Observe that OpenClaw can assemble/projection-bind the per-DM Lossless conversation before returning to the canonical main conversation.

Expected behavior

The runtime policy/session key should only scope policy/sandbox/tool decisions. It should not replace the canonical context-engine session key unless the user/config explicitly selected a per-DM conversation scope.

For a direct Telegram DM whose configured/default conversation is agent:main:main, the Lossless/LCM bootstrap and assemble calls should use:

sessionKey=agent:main:main

A generated per-peer policy key may still be used for tool/sandbox isolation, but it should be passed as a separate policy/sandbox key, not as the context history identity.

Actual behavior

A single inbound Telegram DM at 2026-05-21T18:28:02+07:00 first assembled the stale per-DM LCM conversation, hit the model context limit, sent the generic failure fallback, then assembled the canonical main conversation and sent a second visible message.

Relevant local log evidence from /tmp/openclaw/openclaw-2026-05-21.log:

2026-05-21T18:28:02.266+07:00 Inbound message telegram:<redacted-peer> -> @EvaLabsBot (direct, 4 chars)

2026-05-21T18:28:03.428+07:00 [lcm] bootstrap: session file shrank past checkpoint conversation=1876 session=boot-2026-05-21_07-53-21-505-412ec8bc sessionKey=agent:main:telegram:default:direct:<redacted-peer> checkpointOffset=1897994 currentSize=179112

2026-05-21T18:28:50.843+07:00 [lcm] assemble: done conversation=1876 session=boot-2026-05-21_07-53-21-505-412ec8bc sessionKey=agent:main:telegram:default:direct:<redacted-peer> contextItems=416 summaryContextItems=17 inputMessages=124 outputMessages=417 tokenBudget=258000 estimatedTokens=227240

2026-05-21T18:28:50.888+07:00 codex app-server context-engine projection decision sessionKey=agent:main:telegram:default:direct:<redacted-peer> previousEpoch=summary-prefix-v1:1872:... reason=context-engine-binding-mismatch assembledMessages=417 projectedPromptChars=817231

2026-05-21T18:29:12.721+07:00 embedded run failover decision provider=openai-codex model=gpt-5.5 rawErrorPreview="Codex ran out of room in the model's context window. Start a new thread or clear earlier history before retrying."

2026-05-21T18:29:24.073+07:00 telegram outbound send ok messageId=24348 operation=sendMessage deliveryKind=text

2026-05-21T18:29:22.697+07:00 [lcm] assemble: done conversation=1872 session=boot-2026-05-21_11-15-48-922-1e2fa501 sessionKey=agent:main:main contextItems=165 summaryContextItems=2 inputMessages=125 outputMessages=137 tokenBudget=258000 estimatedTokens=61135

2026-05-21T18:29:22.718+07:00 codex app-server context-engine projection decision sessionKey=agent:main:main previousEpoch=summary-prefix-v1:1876:... reason=context-engine-binding-mismatch assembledMessages=137 projectedPromptChars=166128

2026-05-21T18:29:33.958+07:00 telegram outbound send ok messageId=24349 operation=sendMessage deliveryKind=text
2026-05-21T18:29:33.965+07:00 res ok message.action channel=telegram

The Codex app-server state DB also shows the failed per-DM projection consumed the full window:

thread 019e4a4b-aab0-7c12-8bbd-1f5e13948992 model=gpt-5.5 tokens_used=258400 first_user_message_chars=855222
thread 019e4a4c-1e96-7321-9502-a41c02ae198b model=gpt-5.5 tokens_used=198484 first_user_message_chars=204297

OpenClaw version

2026.5.19

Operating system

macOS 26 / Darwin arm64

Install method

Global OpenClaw gateway managed by launchd (ai.openclaw.gateway)

Model

gpt-5.5 via openai-codex

Provider / routing chain

Telegram polling -> OpenClaw gateway -> embedded agent / Codex app-server -> Lossless context engine -> OpenAI Codex provider

Additional provider/model setup details

Lossless-Claw was verified as the vanilla latest npm package, not a local checkout or branched patch:

/Users/lume/.openclaw/node_modules/@martian-engineering/lossless-claw version=0.11.2
/Users/lume/.openclaw/extensions/node_modules/@martian-engineering/lossless-claw version=0.11.2
/Users/lume/.openclaw/npm/node_modules/@martian-engineering/lossless-claw version=0.11.2

Gateway status at diagnosis:

OpenClaw CLI/server version: 2026.5.19
Gateway pid: 87378
RPC: ok

No local config path explicitly selected per-DM scoping:

session.dmScope: Config path not found
session.scope: Config path not found
session: { "reset": { "mode": "idle", "idleMinutes": 4320 } }
channels.telegram.direct.*.topics.*.agentId = "main"

Logs, screenshots, and evidence

Source-level paths in the installed release build:

/opt/homebrew/lib/node_modules/openclaw/dist/runtime-policy-session-key-0y7qYyqA.js
  resolveRuntimePolicySessionKey() returns buildAgentPeerSessionKey(... dmScope: "per-account-channel-peer") for direct chats when the canonical session key is a main-session alias.

/opt/homebrew/lib/node_modules/openclaw/dist/run-attempt-DI0_-QFr.js
  hookContext.sessionKey = sandboxSessionKey
  bootstrapHarnessContextEngine({ sessionKey: sandboxSessionKey, ... })
  buildCodexWorkspaceBootstrapContext({ sessionKey: sandboxSessionKey, ... })
  assembleHarnessContextEngine({ sessionKey: sandboxSessionKey, ... })

The active LCM conversation rows at diagnosis included both the canonical main lane and stale active per-DM lanes:

1872 | boot-2026-05-21_11-15-48-922-1e2fa501 | agent:main:main | active=1
1876 | boot-2026-05-21_07-53-21-505-412ec8bc | agent:main:telegram:default:direct:<redacted-peer> | active=1
1880 | boot-2026-05-05_11-44-39-074-95d65b06 | agent:main:telegram:default:direct:telegram:<redacted-peer> | active=1

openclaw sessions cleanup --dry-run --fix-dm-scope --active-key agent:main:main --json identified one stale session-store row, but that dry run does not retire stale active LCM conversations:

{
  "dryRun": true,
  "beforeCount": 8,
  "afterCount": 7,
  "dmScopeRetired": 1,
  "wouldMutate": true
}
flowchart TD
  A[Telegram direct DM] --> B[Canonical route/session should be agent:main:main]
  B --> C[Runtime policy resolver derives per-peer policy key]
  C --> D[Policy key passed as sandboxSessionKey]
  D --> E[Context engine bootstrap/assemble uses sandboxSessionKey]
  E --> F[LCM selects stale per-DM conversation 1876]
  F --> G[Prompt projection grows to ~817k chars / full context]
  G --> H[Model fails before reply]
  H --> I[Generic Telegram error fallback]
  B --> J[Next projection uses main conversation 1872]
  J --> K[Agent sends visible reply via message.action]

  classDef bad fill:#ffd6d6,stroke:#cc3333,color:#111;
  class E,F,G,H,I bad;

Impact and severity

Affected: Telegram users where DMs are expected to share the agent main session and stale per-DM LCM/session rows exist from prior runs or prior scoping behavior.

Severity: High / beta blocker. It can cause:

  • one inbound Telegram message to produce both a failure fallback and an agent-authored reply,
  • full-context gpt-5.5 requests from stale history selection,
  • sudden API/token burn,
  • broken expectation that the agent-name main session remains the single continuity lane,
  • confusing LCM compaction behavior because the wrong active conversation is selected.

Additional information

Suggested OpenClaw fix shape:

  1. Keep sessionKey and runtimePolicySessionKey separate in the embedded/Codex app-server run path.
  2. Use the canonical conversation sessionKey for bootstrapHarnessContextEngine(), assembleHarnessContextEngine(), context-engine thread bindings, and workspace/bootstrap memory selection.
  3. Use runtimePolicySessionKey only for policy/sandbox/tool scoping fields.
  4. Add a regression for direct Telegram context where session.dmScope is unset/default-main and ctx.ChatType="direct": context-engine calls should receive agent:main:main, while policy hooks may receive the per-peer policy key.
  5. Consider a companion LCM/OpenClaw cleanup guard for stale active same-file/same-path-shrink conversations whose checkpoint offset is beyond EOF; LCM detected this condition but did not deactivate the stale active row.

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

The runtime policy/session key should only scope policy/sandbox/tool decisions. It should not replace the canonical context-engine session key unless the user/config explicitly selected a per-DM conversation scope.

For a direct Telegram DM whose configured/default conversation is agent:main:main, the Lossless/LCM bootstrap and assemble calls should use:

sessionKey=agent:main:main

A generated per-peer policy key may still be used for tool/sandbox isolation, but it should be passed as a separate policy/sandbox key, not as the context history identity.

Still need to ship something?

×6

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

Back to top recommendations

TRENDING