Problem
notify() in lib/dispatch/notify.ts is runtime-first, but if runtime exists and the channel sender is missing or throws, the notification is dropped instead of falling back to openclaw message send.
This leads to user-visible notification loss for failures like:
Cannot read properties of undefined (reading 'sendMessageTelegram')
Current behavior
The current logic is effectively:
if (runtime) {
await runtime.channel.telegram.sendMessageTelegram(...)
return true
}
await runCommand(["openclaw", "message", "send", ...])
wrapped in an outer try/catch.
That means:
- CLI/OpenClaw fallback is only used when
runtime is absent
- if
runtime is present but runtime.channel.telegram is undefined, or the runtime sender throws, the outer catch logs notify_error and returns false
- the message is never handed off to OpenClaw's normal outbound delivery path
Why this is a bug
Runtime-first is reasonable for performance and for avoiding CLI/WebSocket timeout issues.
But once runtime send fails, notification delivery should still fall back to the standard OpenClaw send path. Right now the failure mode is effectively silent best-effort message loss.
For worker lifecycle notifications, if the user never sees the message, the message was effectively not sent.
Expected behavior
If runtime sender lookup fails, or runtime send throws, notify() should:
- log the runtime failure
- fall back to
openclaw message send
- only return
false if both runtime send and fallback fail
Suggested fix
Refactor sendMessage() so it:
- safely resolves the runtime sender for the selected channel
- uses runtime send only if that sender exists
- on runtime error, tries CLI/OpenClaw fallback
- logs delivery path used, for example:
runtime
cli-fallback
failed
Notes
This is distinct from earlier related issues:
Those explain why runtime-first exists, but they do not address the missing fallback when runtime send itself fails.
Problem
notify()inlib/dispatch/notify.tsis runtime-first, but ifruntimeexists and the channel sender is missing or throws, the notification is dropped instead of falling back toopenclaw message send.This leads to user-visible notification loss for failures like:
Current behavior
The current logic is effectively:
wrapped in an outer
try/catch.That means:
runtimeis absentruntimeis present butruntime.channel.telegramis undefined, or the runtime sender throws, the outer catch logsnotify_errorand returnsfalseWhy this is a bug
Runtime-first is reasonable for performance and for avoiding CLI/WebSocket timeout issues.
But once runtime send fails, notification delivery should still fall back to the standard OpenClaw send path. Right now the failure mode is effectively silent best-effort message loss.
For worker lifecycle notifications, if the user never sees the message, the message was effectively not sent.
Expected behavior
If runtime sender lookup fails, or runtime send throws,
notify()should:openclaw message sendfalseif both runtime send and fallback failSuggested fix
Refactor
sendMessage()so it:runtimecli-fallbackfailedNotes
This is distinct from earlier related issues:
Those explain why runtime-first exists, but they do not address the missing fallback when runtime send itself fails.