OpenClaw

OpenClaw tracks two ways channel session state can outlive the work

OpenClaw records an expired Streamable HTTP notification session and a Telegram delivery mirror that can duplicate assistant messages in transcripts. A related ingress change stops idle retention writes, making lifecycle expiry the common issue.

← Back to homeOriginal source ↗

openclaw/openclaw issue #126100 is the inspected primary source: “fix: Streamable HTTP MCP keeps expired notification session.” The related records below were inspected as supporting context rather than independent confirmation.

The facts

- openclaw/openclaw issue #126100 was created 2026-08-19T00:29:45Z and was open at inspection; its title is “fix: Streamable HTTP MCP keeps expired notification session.” - openclaw/openclaw issue #126090 was created 2026-08-18T23:54:59Z and was open at inspection; its title is “Bug: Telegram channel-final delivery-mirror bypasses text-based dedup, writes duplicate assistant messages to session transcript.” - openclaw/openclaw PR #126073 was created 2026-08-18T23:24:48Z and was open at inspection; its title is “fix(channels): stop idle ingress retention writes.” - The repository reported 386678 stars, 5774 open issues, default branch main, and last push 2026-08-19T01:04:21Z. - The latest tagged-release baseline checked was v2026.8.1-beta.2 published 2026-08-15T05:36:23Z.

What changed

openclaw/openclaw issue #126100 reports: Bug type Behavior bug (incorrect lifecycle state without crash) Beta release blocker No Summary A stateful Streamable HTTP MCP session can remain attached after its initial notification GET returns session-expired HTTP 404. Steps to reproduce 1. On current main (19c916be139), initialize a Streamable HTTP MCP session and return an Mcp-Session-Id. 2. Accept the initialized notification with HTTP 202. 3. Return HTTP 404 from the asynchronous notification GET. 4. Observe that the SDK reports StreamableHTTPError(404) through onerror but OpenClaw does not emit close and leaves the session/catalog attached. Focused reproduction: The added stateful notification-GET case fails before the repair because onclose is never called. Expected behavior An exact stateful notification GET 404 must close the transport through the canonical lifecycle boundary so Gateway/node-host owners retire the stale session and descriptors. Stateful POST requests must not be replayed. Actual behavior OpenClaw closes notification streams only after retry exhaustion. The initial stateful GET 404 is terminal session expiry, but the transport remains attached. OpenClaw version Current main at 19c916be139 Operating system macOS 26 (Darwin 25.6.0) Install method Source checkout with pnpm Model N/A — MCP transport lifecycle reproduces before model execution Provider / routing chain N/A — local Streamable HTTP MCP fixture Logs Impact and severity Affected: operators using stateful Streamable HTTP MCP servers when the server expires or loses a session during

openclaw/openclaw issue #126090 reports: Bug: Telegram channel-final delivery-mirror bypasses text-based dedup, writes duplicate assistant messages to session transcript Summary Every Telegram-originated assistant turn writes a duplicate delivery-mirror assistant message to the session JSONL, parented to the primary assistant message. This is a **different variant** of #94930 (fixed in v2026.6.11 by #95069 for the cache-ttl parenting path). The channel-final identified delivery-mirror path bypasses the text-based dedup check, causing one duplicate per Telegram turn. Environment OpenClaw version: v2026.7.1-2 Channel: Telegram (DM, direct conversation) Does NOT reproduce on WebChat (confirmed — 0 duplicates in WebChat session JSONL) Reproduction 1. Send a message to an OpenClaw agent via Telegram 2. Wait for the assistant reply to be delivered 3. Inspect the session JSONL for that turn 4. Observe two assistant messages with identical text content: the primary (from agent runner) and a delivery-mirror copy Observed behavior In a single Telegram session (841 entries, 381 assistant messages), **21 duplicate groups** were found — one delivery-mirror duplicate per assistant turn. Each duplicate: **ID format:** UUID (36-char, e.g. 57af1f64-86b2-4279-bc9a-18f5632383f1) — from randomUUID() in appendSessionTranscriptMessageLocked **Parent:** the primary assistant message ID (8-char hash, e.g. a70ec279) **Model:** delivery-mirror, **Provider:** openclaw **Content:** byte-for-byte identical to the primary's text content **Delay:** 0.9–2.6s after the primary **Idempotency key:** telegram-final:agent:main:telegram:direct::::0 (unique per delivery) **Delivery mirror:** { kind: "channel-final", sourceMessageId: "telegram-final:..." } The primary assistant

openclaw/openclaw PR #126073 reports: Closes #126033 What Problem This Solves Fixes an issue where idle Discord, Signal, Microsoft Teams, LINE, and SMS monitors repeatedly opened SQLite retention transactions on every 500ms or 1s drain poll, even when no messages had arrived. Those needless write-lock attempts amplified contention with audit and other shared-state writers and could surface as database is locked ingress failures. Why This Change Was Made The shared monitor migration preserved channels' historical admission-time pruning with pruneIntervalMs: 0, but interpreted zero as “always due” inside the timer-driven pump. This change restores the original owner boundary centrally: zero/negative intervals prune once per external admit or admitBatch, while positive intervals retain startup and timed-pump pruning. Retention caps, TTLs, queue transactions, and all five plugin call sites remain unchanged. This is an AI-assisted maintainer repair. User Impact Idle durable channel accounts no longer perform 3,600–7,200 unnecessary shared-state retention transactions per hour. Incoming messages still prune before enqueueing, including exactly once for a multi-event batch, so replay-guard retention behavior remains intact. Production diff: +12/-4 (net +8), justified by making the admission-versus-pump ownership state explicit in the shared monitor. Test diff: +70/-3 (net +67). Evidence Real SQLite reproduction before the fix: 7 prune calls in 65ms with zero admitted events. Same reproduction after the fix: {"idlePrunes":0,"admissionOperations":2,"totalPrunes":2}. Exact rebased focused tests: 6 Vitest shards, 111 tests passed across shared

Why it matters

Session state that survives past its owner can duplicate delivery, retain stale notifications or rewrite idle ingress history. Expiry must be enforced at every channel boundary. The operator test is whether the system remains bounded and its receipts still describe the action after failure, retry or restart.

Current

The primary record was open when captured on 2026-08-19. The tagged-release baseline was v2026.8.1-beta.2 published 2026-08-15T05:36:23Z. Repository metadata, full source bodies, current pull requests and issues, releases, Google News, Hacker News, Lobsters, Metamesh and the rendered ClawCharts row were inspected. ClawCharts selected the subject; it did not prove the claim.

Evidence

The primary URL is https://github.com/openclaw/openclaw/issues/126100. Supporting records are https://github.com/openclaw/openclaw/issues/126090 and https://github.com/openclaw/openclaw/pull/126073. Source bodies, timestamps and states are preserved in the daily evidence bundle. Test counts and reproductions remain attributed to their authors unless identified as independently rerun.

Source boundary

Open work is described as open, closed work as closed, and operator reports as reports. A pull request is evidence of proposed or reviewed direction, not proof of a shipped release. Search residue, package mirrors and historically published source spines were excluded.

Operator take

Give notification sessions and delivery mirrors explicit owners and expiry, deduplicate before transcript persistence, and stop retention writes when ingress is idle. Preserve a before-state receipt, make the smallest reversible change, and verify the original failure independently.

Caveat

Public project records are mutable. Status, scope and evidence can change after publication. This brief records the inspected state and does not authorize changes to a reader’s deployment.

Source inspected; source state, environment and release boundary remain explicit.