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
- Run OpenClaw 2026.4.27 with the Matrix channel enabled.
- 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.
- 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).
- Inspect
~/.openclaw/cron/jobs.json for the created job.
- 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 openclaw@2026.4.27), 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 main → claude-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:
- 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
- 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.
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 wheremcp__openclaw__cron action=addwithsessionTarget: "current"(and no explicitdelivery) is invoked from a Claude CLI subprocess via the MCP loopback HTTP server. The created cron job still stores a lowercased Matrix room ID indelivery.to, causing the sameM_UNKNOWN: non-create event for room of unknown version [500]error and infinite retry loop (deleteAfterRun: truenever applies because runs always fail).Reproduced on 2026.4.27 (latest stable, published 2026-04-29).
Steps to reproduce
main) that usesclaude-clias backend (liveSession: claude-stdio), so it spawns aclaudesubprocess that talks to the MCP loopback over HTTP.!c9p9XFWiH5Szl4yZiP:matrix.example), ask the agent to schedule a one-shot reminder (mcp__openclaw__cron action=add,sessionTarget: "current", nodelivery).~/.openclaw/cron/jobs.jsonfor the created job.Expected behavior
After fix #71798,
currentDeliveryContext.toshould preserve the case-sensitive Matrix room ID and the crondelivery.toshould be the canonical-cased ID (e.g.!c9p9XFWiH5Szl4yZiP:...). The scheduled message delivers successfully anddeleteAfterRun: trueremoves the job after one run.Actual behavior
The created cron job stores lowercased
sessionTargetanddelivery.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 versionand the job retries indefinitely (3 errors observed in 5 minutes, backoff schedule 30s → 60s → 5min → 15min → 60min). Because the run is neverlastRunStatus: "ok",deleteAfterRun: truenever triggers.Worse: each failed cron run takes the embedded code path which uses
provider=anthropicdirectly (notclaude-clisubprocess). Combined with Anthropic's recent third-party app billing rejection (HTTP 400Third-party apps now draw from your extra usage), every retry pollutes logs with cascading fallback failures acrossanthropic/claude-opus-4-7 → anthropic/claude-sonnet-4-6 → anthropic/claude-opus-4-6 → ollama-cloud/....Hypothesis on root cause
The fix in
e309fd485eintroducesinferDeliveryFromContext(opts.currentDeliveryContext)increateCronTool, withcurrentDeliveryContext.tosourced fromoptions.currentChannelId ?? options.agentTo(line ~8880 inopenclaw-tools-*.js). The non-embedded code path wires this correctly.In our case (MCP loopback HTTP from a Claude CLI subprocess in
claude-stdiolive session mode):createCronToolinstance. The HTTP path may instantiate the cron tool through a different wiring that does not populatecurrentDeliveryContext, falling back toinferDeliveryFromSessionKey(agentSessionKey)which uses the lowercasedparseAgentSessionKeyoutput (session-key-utils-*.jsnormalizeOptionalLowercaseString).currentChannelIditself is already lowercased in the request context before reaching the loopback handler (e.g. derived fromoriginToof 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 openclaw@2026.4.27), 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
main→claude-clibackend (subprocess) → MCP loopback HTTP →mcp__openclaw__cronWorkaround
Force every cron creation that should deliver to a Matrix room to include
deliveryexplicitly with the canonical-casedto:{ "delivery": { "mode": "announce", "channel": "matrix", "to": "!c9p9XFWiH5Szl4yZiP:matrix.devlabz.eu" } }Documented this as a hard rule in our agent's
AGENTS.mdso the LLM never relies on the implicitsessionTarget: "current"derivation for Matrix.Logs, screenshots, and evidence
Suggested fix direction
Either:
currentDeliveryContextis populated in the MCP loopback HTTP path the same way it is for the in-process tool (line 8876 in bundledopenclaw-tools), by reading the room ID from the session store (origin.nativeChannelIdis preserved with correct casing in~/.openclaw/agents/<id>/sessions/sessions.json), orinferDeliveryFromSessionKey, instead of using the lowercasedagentSessionKey, 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.