Skip to content

[Bug]: cron with sessionTarget=current still lowercases Matrix roomId in 2026.4.27 (regression of #71798 via MCP loopback path) #75261

Description

@sk7n4k3d

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

The fix from #71798 (commit e309fd485e, released in 2026.4.25) does not cover the case where mcp__openclaw__cron action=add with sessionTarget: "current" (and no explicit delivery) is invoked from a Claude CLI subprocess via the MCP loopback HTTP server. The created cron job still stores a lowercased Matrix room ID in delivery.to, causing the same M_UNKNOWN: non-create event for room of unknown version [500] error and infinite retry loop (deleteAfterRun: true never applies because runs always fail).

Reproduced on 2026.4.27 (latest stable, published 2026-04-29).

Steps to reproduce

  1. Run OpenClaw 2026.4.27 with the Matrix channel enabled.
  2. Configure an agent (e.g. main) that uses claude-cli as backend (liveSession: claude-stdio), so it spawns a claude subprocess that talks to the MCP loopback over HTTP.
  3. From a Matrix room with uppercase characters in the room ID (e.g. !c9p9XFWiH5Szl4yZiP:matrix.example), ask the agent to schedule a one-shot reminder (mcp__openclaw__cron action=add, sessionTarget: "current", no delivery).
  4. Inspect ~/.openclaw/cron/jobs.json for the created job.
  5. Wait for the cron to fire.

Expected behavior

After fix #71798, currentDeliveryContext.to should preserve the case-sensitive Matrix room ID and the cron delivery.to should be the canonical-cased ID (e.g. !c9p9XFWiH5Szl4yZiP:...). The scheduled message delivers successfully and deleteAfterRun: true removes the job after one run.

Actual behavior

The created cron job stores lowercased sessionTarget and delivery.to:

{
  "name": "ping-salon-22h37",
  "agentId": "main",
  "sessionKey": "agent:main:matrix:channel:!c9p9xfwih5szl4yzip:matrix.devlabz.eu",
  "schedule": {"kind": "at", "at": "2026-04-30T20:37:00.000Z"},
  "sessionTarget": "session:agent:main:matrix:channel:!c9p9xfwih5szl4yzip:matrix.devlabz.eu",
  "deleteAfterRun": true,
  "delivery": {
    "mode": "announce",
    "to": "!c9p9xfwih5szl4yzip:matrix.devlabz.eu",
    "channel": "matrix"
  }
}

Each run errors with M_UNKNOWN: MatrixError: [500] non-create event for room of unknown version and the job retries indefinitely (3 errors observed in 5 minutes, backoff schedule 30s → 60s → 5min → 15min → 60min). Because the run is never lastRunStatus: "ok", deleteAfterRun: true never triggers.

Worse: each failed cron run takes the embedded code path which uses provider=anthropic directly (not claude-cli subprocess). Combined with Anthropic's recent third-party app billing rejection (HTTP 400 Third-party apps now draw from your extra usage), every retry pollutes logs with cascading fallback failures across anthropic/claude-opus-4-7 → anthropic/claude-sonnet-4-6 → anthropic/claude-opus-4-6 → ollama-cloud/....

Hypothesis on root cause

The fix in e309fd485e introduces inferDeliveryFromContext(opts.currentDeliveryContext) in createCronTool, with currentDeliveryContext.to sourced from options.currentChannelId ?? options.agentTo (line ~8880 in openclaw-tools-*.js). The non-embedded code path wires this correctly.

In our case (MCP loopback HTTP from a Claude CLI subprocess in claude-stdio live session mode):

  • The cron tool is reached via the loopback HTTP server, not the in-process createCronTool instance. The HTTP path may instantiate the cron tool through a different wiring that does not populate currentDeliveryContext, falling back to inferDeliveryFromSessionKey(agentSessionKey) which uses the lowercased parseAgentSessionKey output (session-key-utils-*.js normalizeOptionalLowercaseString).
  • Or currentChannelId itself is already lowercased in the request context before reaching the loopback handler (e.g. derived from originTo of a session whose store entry has lowercased channelId).

OpenClaw version

2026.4.27

Operating system

Linux 7.0.0-1-cachyos (Arch CachyOS)

Install method

Global npm install (npm install -g [email protected]), running as systemd user unit on edge node.

Model

claude-cli/claude-opus-4-7 (primary), with liveSession: claude-stdio (Claude CLI subprocess, MCP loopback HTTP)

Provider / routing chain

Matrix room → agent mainclaude-cli backend (subprocess) → MCP loopback HTTP → mcp__openclaw__cron

Workaround

Force every cron creation that should deliver to a Matrix room to include delivery explicitly with the canonical-cased to:

{
  "delivery": {
    "mode": "announce",
    "channel": "matrix",
    "to": "!c9p9XFWiH5Szl4yZiP:matrix.devlabz.eu"
  }
}

Documented this as a hard rule in our agent's AGENTS.md so the LLM never relies on the implicit sessionTarget: "current" derivation for Matrix.

Logs, screenshots, and evidence

2026-04-30T22:38:36 [agent/embedded] embedded run agent end: runId=553822d6-... isError=true
  model=claude-opus-4-7 provider=anthropic
  error=LLM request rejected: Third-party apps now draw from your extra usage,
  not your plan limits.

2026-04-30T... [cron] last error:
  M_UNKNOWN: MatrixError: [500] non-create event for room of unknown version
  in !c9p9xfwih5szl4yzip:matrix.devlabz.eu
  (https://matrix.devlabz.eu/_matrix/client/v3/rooms/%21c9p9xfwih5szl4yzip%3Amatrix.devlabz.eu/send/m.room.message/...)

# jobs-state.json:
"state": {
  "lastRunStatus": "error",
  "lastStatus": "error",
  "consecutiveErrors": 3,
  "lastError": "M_UNKNOWN: MatrixError: [500] non-create event for room of unknown version in !c9p9xfwih5szl4yzip:matrix.devlabz.eu"
}

Suggested fix direction

Either:

  1. Ensure currentDeliveryContext is populated in the MCP loopback HTTP path the same way it is for the in-process tool (line 8876 in bundled openclaw-tools), by reading the room ID from the session store (origin.nativeChannelId is preserved with correct casing in ~/.openclaw/agents/<id>/sessions/sessions.json), or
  2. In inferDeliveryFromSessionKey, instead of using the lowercased agentSessionKey, look up the canonical channel ID from the session store using the parsed agentId/rest tuple — Matrix room IDs (and other case-sensitive provider IDs) should be re-canonicalized from the store rather than reconstructed from a lowercased session key.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions