Fix: OpenClaw Cron Jobs Created But Never Fire
Created a cron job in OpenClaw via the API but it never runs? It's probably missing nextRunAtMs. Here's why and how to fix it with the CLI instead.
Fix: OpenClaw Cron Jobs Created But Never Fire
TL;DR: Cron jobs created via the API are missing the nextRunAtMs field, so the scheduler never picks them up. Use the CLI to create cron jobs instead.
The Error
There's no error message — that's what makes this so frustrating. The cron job is created successfully:
# API call succeeds
curl -X POST http://localhost:3100/api/crons \
-H "Content-Type: application/json" \
-d '{
"name": "daily-summary",
"schedule": "0 9 * * *",
"action": "send",
"message": "Good morning! Here is your daily summary.",
"channel": "telegram"
}'
# Response: 200 OK, job created
{
"id": "cron_abc123",
"name": "daily-summary",
"schedule": "0 9 * * *",
"status": "active"
}
Everything looks fine. But 9am comes and goes. Nothing happens. The job just... never fires.
If you inspect the stored cron job, you'll notice:
{
"id": "cron_abc123",
"name": "daily-summary",
"schedule": "0 9 * * *",
"status": "active",
"nextRunAtMs": null
}
nextRunAtMs is null. The scheduler checks this field to know when to run the job next. No value = no run.
Why This Happens
OpenClaw's cron scheduler uses nextRunAtMs (a Unix timestamp in milliseconds) to determine the next execution time. When you create a cron job through the CLI, it automatically calculates this value from the cron schedule and sets it. When you create one through the API, this calculation is skipped — the job is stored without a next-run timestamp.
The scheduler loop works like this:
every 60 seconds:
for each cron job:
if job.nextRunAtMs <= now:
execute(job)
job.nextRunAtMs = calculateNext(job.schedule)
If nextRunAtMs is null, the condition null <= now is false, so the job is silently skipped. Every time. Forever.
This is a bug in the API handler — it should calculate nextRunAtMs on creation, but it doesn't.
How to Fix It
Option A: Use the CLI instead of the API (recommended)
The CLI correctly sets nextRunAtMs:
# Create a cron job via CLI
openclaw cron create \
--name "daily-summary" \
--schedule "0 9 * * *" \
--action send \
--message "Good morning! Here's your daily summary." \
--channel telegram
Verify it was created with a next-run time:
openclaw cron list
You should see:
NAME SCHEDULE NEXT RUN STATUS
daily-summary 0 9 * * * 2026-02-04 09:00 UTC active
Option B: Patch the nextRunAtMs manually
If you've already created jobs via the API and don't want to recreate them, you can set nextRunAtMs directly:
# Calculate the next run time (e.g., tomorrow at 9am UTC)
# Unix timestamp in milliseconds
NEXT_RUN=$(date -d "tomorrow 09:00:00 UTC" +%s%3N)
# Update the cron job via API
curl -X PATCH http://localhost:3100/api/crons/cron_abc123 \
-H "Content-Type: application/json" \
-d "{\"nextRunAtMs\": $NEXT_RUN}"
Or if you have the jq and node commands available, calculate it from the cron expression properly:
# Using node to calculate next cron occurrence
NEXT_RUN=$(node -e "
const parser = require('cron-parser');
const interval = parser.parseExpression('0 9 * * *');
console.log(interval.next().getTime());
")
curl -X PATCH http://localhost:3100/api/crons/cron_abc123 \
-H "Content-Type: application/json" \
-d "{\"nextRunAtMs\": $NEXT_RUN}"
Option C: Fix it in the API source code
If you want to fix the root cause, find the cron creation handler in the OpenClaw source:
grep -r "cron.*create\|createCron\|POST.*cron" \
~/.config/openclaw/ /usr/lib/openclaw/ node_modules/openclaw/ 2>/dev/null
Look for the handler that creates cron jobs and add the nextRunAtMs calculation:
// After creating the cron job object, add:
const parser = require('cron-parser');
const interval = parser.parseExpression(cronJob.schedule);
cronJob.nextRunAtMs = interval.next().getTime();
Then restart:
openclaw gateway restart
Verify the fix
After creating or patching the cron job, wait for the scheduled time and check the logs:
# Watch for cron execution
openclaw logs --tail 100 --follow | grep -i cron
# Or check cron job status
openclaw cron list
How to Prevent It
- Use the CLI for creating cron jobs until the API bug is fixed. The CLI has the correct initialization logic.
- Always verify
nextRunAtMsafter creating a cron job. If it'snullor missing, the job won't run. - Test with a short interval first. Before setting up a daily cron, create one that runs every 5 minutes (
*/5 * * * *) to verify the scheduler is working:
openclaw cron create \
--name "test-cron" \
--schedule "*/5 * * * *" \
--action send \
--message "Cron test — if you see this, it's working" \
--channel telegram
Delete it after confirming:
openclaw cron delete test-cron
The Easy Way
lobsterfarm is a managed hosting service for OpenClaw — deployment, updates, and support handled for you.
Skip the setup. Start using your AI assistant today.
lobsterfarm gives you a fully managed OpenClaw instance — one click, your own server, running 24/7.