#WhatsApp group send from cron job keeps failing
1 messages · Page 1 of 1 (latest)
Let me check the current cron docs and source, because this one smells like the cron delivery model is fighting your prompt rather than WhatsApp itself.
Yep, there is a supported path here, and your current JSON-action pattern is fighting it.
I checked the docs and cron behavior. For isolated cron jobs with delivery enabled, OpenClaw owns the final send path. In that mode, it expects the agent to return plain text, and it does not want the agent to call the message tool itself.
So, directly answering your 3 questions:
-
Idiomatic way
- Use the cron job’s own delivery config:
--session isolated--announce--channel whatsapp--to "120363424724127698@g.us"
- Then have the job return the final message body as plain text.
- WhatsApp group JIDs are supported targets.
- Use the cron job’s own delivery config:
-
Recommended cron payload pattern
- Do not emit
{"action":"send_whatsapp",...}and hope the model interprets it.
- Do not emit
- Do this instead:
openclaw cron edit wa-group-briefing \
--announce \
--channel whatsapp \
--to "120363424724127698@g.us"
Prompt pattern:
Run the Python script.
If stdout is empty, return NO_REPLY.
Otherwise return stdout verbatim as plain text only.
Do not output JSON.
Do not call the message tool.
Do not add commentary, code fences, or explanation.
That lines up with how cron delivery is designed.
- Different mechanism?
- If you want OpenClaw-managed scheduling: use cron + announce, as above.
- If you want exact deterministic forwarding of script output with zero model mediation: skip the agent entirely and have the script or wrapper call:
openclaw message send --channel whatsapp --target "120363424724127698@g.us" --message "..."
- I would not use a skill for this. It adds complexity without solving the core issue.
- There is not currently a “direct tool invocation payload” for cron that bypasses the agent turn.
Two important gotchas:
--no-deliverkeeps the run internal. It does not hand delivery back to the agent.
- If the run returns exactly
NO_REPLY, cron suppresses outbound delivery cleanly. That’s the right “send nothing” path.
Quick sanity test before touching cron:
openclaw message send \
--channel whatsapp \
--target "120363424724127698@g.us" \
--message "cron test"
If that works, your WhatsApp target/auth is fine, and the remaining issue is just cron payload design.
Docs:
If you want, paste your current openclaw cron list --json entry for wa-group-briefing, and I can rewrite it into the clean version.
Ah, yep, the pasted job makes the bug much clearer.
You currently have two conflicting delivery paths:
-
sessionTarget: "isolated"+delivery.mode: "announce"
→ cron owns delivery -
Your prompt says
→ parse stdout JSON and call the WhatsApp message tool
For isolated + announce jobs, that second part is the wrong pattern.
Also, there’s a target mismatch:
- what you want:
120363424724127698@g.us(WhatsApp group) - what the job is configured to deliver to:
+919962527839(a DM target)
So even if delivery works, it’s currently aimed at the phone number, not the group.
What I’d change
1. Change delivery.to to the group JID
"delivery": {
"mode": "announce",
"channel": "whatsapp",
"to": "120363424724127698@g.us"
}
2. Replace the payload prompt
Use this instead:
Run: python3 /home/node/.openclaw/workspace/skills/briefings/scripts/wa_group_briefing.py
If stdout is empty, return NO_REPLY.
Otherwise return stdout verbatim as plain text only.
Do not output JSON.
Do not call the message tool.
Do not add commentary, code fences, or explanation.
Why this should work
With isolated + announce, OpenClaw expects the run to return plain text, then cron sends that text to the configured target automatically.
So the model should not be deciding “do I call WhatsApp?”.
That decision is already made by:
"delivery": {
"mode": "announce",
"channel": "whatsapp",
"to": "..."
}
One useful clue from your state
This part:
"lastDelivered": true,
"lastDeliveryStatus": "delivered"
is actually good news. It suggests the WhatsApp delivery pipeline itself is probably fine. The bad part is the agent response contract, not the channel transport.
Quick test
Before rerunning the cron, test the exact group target once:
openclaw message send \
--channel whatsapp \
--target "120363424724127698@g.us" \
--message "group delivery test"
If that lands in the group, you’re basically done.
Short version
Your permanent fix is:
- keep
sessionTarget: isolated - keep
delivery.mode: announce - set
delivery.toto the group JID - make the script output be returned as plain text
- use
NO_REPLYfor “send nothing” - stop asking the agent to interpret JSON and call the message tool
Docs:
- https://docs.openclaw.ai/automation/cron-jobs
- https://docs.openclaw.ai/cli/cron
- https://docs.openclaw.ai/cli/message
If you want, paste the edited cron JSON after you change those two fields, and I’ll sanity-check it before you run it.
I want to be precise on the multi-recipient case, because that’s where the clean “cron announce” pattern stops being a great fit.
Short answer: no, not with isolated + announce.
I checked the cron shape in source, and cron delivery is basically one target per job:
delivery.channeldelivery.to
There isn’t a multi-target or per-run dynamic-recipient announce shape for cron jobs right now.
So the rule of thumb is
-
One fixed recipient/group per cron job
- use
isolated + announce - return plain text
- let cron deliver it
- use
-
Different recipients chosen at runtime
- do not use
isolated + announceas the send mechanism- use a different pattern
Best patterns for dynamic recipients
1. Best for deterministic/script-driven routing
Have the script or wrapper send directly with openclaw message send.
That’s the cleanest option when your Python code already knows:
- who to send to
- what to send
- whether to send at all
Examples:
- same message to many people: use
openclaw message sendwith repeated--targets - different message per person: call
openclaw message sendonce per recipient
I’d recommend this for your “Balaji / Reva / Maya in one run” case.
2. If you really want the agent deciding recipients/content
Use an isolated cron job with no announce delivery and let the agent call the message tool itself.
But that puts you back into LLM tool-calling reliability land, so I would not use it for exact scripted fan-out unless you actually want model judgment in the loop.
3. If recipients are fixed and small
Split into multiple cron jobs, one per target.
Boring, but very robust.
My recommendation
For your setup:
- WA group briefing → keep as
isolated + announceto the group JID