Skip to content

[Bug]: wake() in cron/service/timer.ts calls enqueueSystemEvent without sessionKey — system events silently dropped #19438

@destructatron

Description

@destructatron

Summary

openclaw system event --text "..." --mode now silently fails to deliver events. The CLI returns ok, the heartbeat fires, but the system event is never queued because wake() in src/cron/service/timer.ts calls enqueueSystemEvent(text) without passing a sessionKey.

This is a regression from the fix for #510, which correctly added session key resolution to cron job execution paths (line 454) but missed the wake() function (line 632) in the same file.

Steps to reproduce

  1. Set up any integration that calls openclaw system event --text "..." --mode now (e.g. an IRC mention watcher)
  2. Trigger the event while no user message is active
  3. CLI returns ok
  4. Agent is never woken — event is silently dropped

The event appears to work if a user message arrives at the same time, because the system event gets bundled into that turn's context. But standalone --mode now wakes never trigger an agent turn.

Root cause

wake() at src/cron/service/timer.ts:632:

state.deps.enqueueSystemEvent(text);  // ← no sessionKey or agentId

The enqueueSystemEvent wrapper in server-cron.ts:158 resolves the session key from agentId, but wake() passes neither. The underlying requireSessionKey() in system-events.ts throws on empty keys, and the error is swallowed upstream.

Compare with cron job execution at line 454 which correctly passes both:

state.deps.enqueueSystemEvent(text, {
  agentId: job.agentId,
  sessionKey: job.sessionKey,
  contextKey: \`cron:\${job.id}\`,
});

And the HTTP hooks path in server/hooks.ts which also works correctly:

enqueueSystemEvent(value.text, { sessionKey });

Fix

Three-line change — pass agentId to the wrapper so it can resolve the session key:

 export function wake(
   state: CronServiceState,
   opts: { mode: "now" | "next-heartbeat"; text: string },
 ) {
   const text = opts.text.trim();
   if (!text) {
     return { ok: false } as const;
   }
-  state.deps.enqueueSystemEvent(text);
+  const agentId = state.deps.defaultAgentId ?? DEFAULT_AGENT_ID;
+  state.deps.enqueueSystemEvent(text, { agentId });
   if (opts.mode === "now") {
-    state.deps.requestHeartbeatNow({ reason: "wake" });
+    state.deps.requestHeartbeatNow({ reason: "wake", agentId });
   }
   return { ok: true } as const;
 }

Environment

  • OpenClaw version: 2026.2.16 (b251533)
  • OS: Linux 6.18.9-200.fc43.x86_64 (Fedora 43)
  • Node: v22.22.0
  • Install method: pnpm build from source

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions