Troubleshooting · AI agents

Scheduled AI agent not running? Diagnose it fast

Why a scheduled agent or LLM pipeline stops producing output — dead trigger, rate limits, hung API calls, deprecated models, silent agent failures — and how to fix each.

A scheduled agent can stop in two places: the scheduler that triggers it, or the agent itself. Walk these in order.

1. Did the trigger fire at all?

Before debugging the agent, confirm something actually started it. Check the scheduler layer’s own log first:

grep run_agent /var/log/syslog          # plain cron
kubectl get jobs --sort-by=.metadata.creationTimestamp   # Kubernetes CronJob

Each trigger has its own failure modes — see Docker cron not running, Kubernetes CronJob not running or GitHub Actions schedule not running. If nothing started the process, stop here: the problem is the trigger, not the agent.

2. Rate limits, spend caps, and dead API keys

The most common agent-specific cause. A 429 storm, an exhausted monthly budget, or an API key someone rotated all end the run before it produces anything:

python run_agent.py 2>&1 | grep -iE "429|rate.?limit|quota|401|invalid.*key"

Check the provider’s usage dashboard, and log the raw API error — an agent loop that catches the exception and paraphrases it (“I was unable to complete the task”) destroys exactly the information you need right now.

3. The run hangs on a stuck API call

Many SDKs ship without a request timeout. One wedged connection and the run never finishes — and depending on your cron setup, the next runs pile up behind it. Bound both the call and the whole run:

# crontab: hard deadline for the entire run, no overlapping instances
0 2 * * * flock -n /tmp/agent.lock timeout 30m python run_agent.py

And set the SDK-level timeout explicitly (timeout=60 or equivalent) so one slow generation can’t eat the whole deadline.

4. The model or API changed underneath you

Providers deprecate model IDs and reshape responses on their own schedule. Your job breaks without any deploy on your side. Symptoms: sudden 400/404 on the model name, or parsing errors on a response that used to work.

Pin what you can — an explicit, dated model version and a locked SDK version — so upgrades happen when you choose, not when the provider does:

# requirements.txt — pin the SDK, don't float on "latest"
openai==1.54.3

5. The agent “succeeded” but produced nothing

Exit code 0 means the process ended, not that work happened. Agent loops swallow tool errors by design: the search tool failed, the model apologized, the loop completed “successfully” with nothing written. Validate the artifact, not the exit code:

python run_agent.py --task nightly-digest
test -s out/digest.md || { echo "empty digest" >&2; exit 1; }

The deeper problem: for an unattended agent, silence looks like success

Every cause above ends the same way — no output, and nothing that tells you. The trigger won’t report a dead schedule, the provider won’t report your spend cap, and the agent won’t report its own empty run.

Have the run ping a heartbeat only after its output is validated. If a valid result stops arriving — for any of the reasons above — the ping is missed and you’re alerted, independent of which layer broke:

curl -fsS https://ping.steadycron.com/<your-ping-token>/start
python run_agent.py --task nightly-digest && test -s out/digest.md \
  && curl -fsS https://ping.steadycron.com/<your-ping-token> \
  || curl -fsS https://ping.steadycron.com/<your-ping-token>/fail

See Cron jobs for AI agents for the full pattern — including moving the trigger itself to an HTTP job, so scheduling, retries, and alerting live outside the box that runs the agent. For why this matters more for agents than for plain cron, see Dead man’s switch for AI agents.