Cron Job Running Twice — Why & How to Fix Duplicate Runs
Your cron job is executing more often than it should. Here's how to find the duplicate and stop it.
Quick Diagnostic Checklist
crontab -l | sort | uniq -d
ls /etc/cron.d/ /etc/cron.daily/
ps aux | grep your-script
cat /etc/anacrontab
A cron job running twice can cause real damage: duplicate emails sent to customers, double database entries, duplicate charges, or corrupted data from concurrent writes. This guide covers every cause of duplicate cron execution and the exact fix for each.
1. Duplicate Crontab Entries
The simplest and most common cause. You (or a deploy script) added the same cron entry twice. This is especially common when crontab entries are added programmatically via crontab -l | { cat; echo "..."; } | crontab - without checking if the entry already exists.
Diagnose it: List your crontab and look for duplicates:
# Show your crontab
crontab -l
# Find exact duplicates
crontab -l | sort | uniq -d
Fix it: Edit your crontab and remove the duplicate line:
crontab -e
If your deploy scripts add cron entries, fix them to check for existing entries first:
# Safe way to add a cron entry (only if it doesn't exist)
(crontab -l 2>/dev/null | grep -v "/path/to/script.sh"; echo "0 2 * * * /path/to/script.sh") | crontab -
2. Same Job in User Crontab AND System Cron
There are multiple places cron jobs can be defined. If the same job appears in two locations, it runs twice:
- User crontab — edited with
crontab -e - /etc/crontab — the system crontab
- /etc/cron.d/ — drop-in cron files
- /etc/cron.daily/, /etc/cron.hourly/, etc. — periodic directories
Diagnose it: Check all locations for your script:
# User crontab
crontab -l
# System crontab
cat /etc/crontab
# Drop-in directory
ls /etc/cron.d/
grep -r "your-script" /etc/cron.d/
# Periodic directories
grep -r "your-script" /etc/cron.daily/ /etc/cron.hourly/ /etc/cron.weekly/ /etc/cron.monthly/
Fix it: Remove the duplicate from whichever location is incorrect. Typically, keep it in the user crontab and remove it from the system-wide files (or vice versa).
Track exactly when and how often your cron jobs run with CronSignal.
Sign up with Google3 monitors free. No credit card.
3. Overlapping Executions — Job Takes Longer Than the Interval
If your cron job runs every 5 minutes but the job itself takes 7 minutes to complete, the second instance starts while the first is still running. This is not technically running "twice" at the scheduled time — it's two instances running concurrently, which can be even worse.
Diagnose it: Check if multiple instances are running:
# Check for running instances
ps aux | grep your-script.sh
# Count instances
pgrep -c -f your-script.sh
Fix it: Use flock to create a file lock. This is the standard, reliable solution:
# In your crontab:
*/5 * * * * /usr/bin/flock -n /tmp/myjob.lock /path/to/script.sh
The -n flag means "non-blocking" — if the lock is already held by a running instance, the new instance exits immediately instead of waiting. The lock is automatically released when the process finishes.
You can also implement locking inside your script:
#!/bin/bash
LOCKFILE="/tmp/myjob.lock"
# Try to get the lock
exec 200>"$LOCKFILE"
flock -n 200 || { echo "Already running"; exit 1; }
# Your actual job logic here
/usr/bin/python3 /home/user/app/process.py
# Lock is released automatically when script exits
4. Anacron + Cron Overlap
Anacron is designed to run missed jobs after a system wakes up or boots. If you have the same job configured in both cron and anacron, it can execute twice — once by cron at the scheduled time, and once by anacron when it catches up.
Diagnose it: Check anacron configuration:
cat /etc/anacrontab
And compare with your cron entries. On many distributions, /etc/cron.daily/ and similar directories are actually run by anacron, not cron. Check:
# On Debian/Ubuntu, this is often in /etc/crontab:
cat /etc/crontab | grep -i anacron
# Or check if anacron is handling the periodic directories:
ls -la /etc/cron.daily/0anacron
Fix it: Keep the job in one system only. If you're using /etc/cron.daily/, let anacron handle it and remove the equivalent entry from your user crontab. Or vice versa — use the user crontab with a specific schedule and remove the script from /etc/cron.daily/.
5. Daylight Saving Time Causing Double Runs
When clocks "fall back" for DST (e.g., 2:00 AM becomes 1:00 AM), any cron job scheduled between 1:00 AM and 2:00 AM will run twice — once before the clock change and once after, because that hour happens twice.
Example: A job scheduled at 0 1 * * * (1:00 AM) in the US Eastern timezone will run twice on the first Sunday of November.
Fix option 1: Schedule jobs outside the DST transition window (avoid 1:00 AM - 3:00 AM):
# Instead of 1 AM, run at 4 AM
0 4 * * * /path/to/script.sh
Fix option 2: Use UTC for your cron daemon, which has no DST transitions:
# Set timezone at the top of your crontab
TZ=UTC
0 6 * * * /path/to/script.sh
Fix option 3: Use flock as a safety net, so even if cron triggers twice, only one instance runs:
0 1 * * * /usr/bin/flock -n /tmp/nightly-backup.lock /path/to/backup.sh
The Universal Fix: flock
Regardless of the root cause, adding flock to any cron job prevents concurrent execution. It's a best practice for any job where duplicate runs would be harmful:
# Template for any cron job with flock protection
*/5 * * * * /usr/bin/flock -n /tmp/JOBNAME.lock /path/to/script.sh
Key points about flock:
-n— exit immediately if lock is held (don't queue up)-w 60— wait up to 60 seconds for the lock before giving up- The lock file is automatically created if it doesn't exist
- The lock is automatically released when the process exits (even on crash)
- Use a unique lock file path per job
Monitor Your Cron Job Frequency
Once you've fixed the duplicate execution, how do you know it stays fixed? A deployment could re-add a duplicate entry. A system update could re-enable anacron. The next DST transition could trigger a double run.
CronSignal tracks exactly when your cron jobs ping in. If a job that should run once per hour suddenly pings twice, you'll see it immediately in your dashboard. Set up monitoring in 30 seconds:
0 2 * * * /usr/bin/flock -n /tmp/backup.lock /home/scripts/backup.sh && curl -fsS https://api.cronsignal.io/ping/your-check-id
The heartbeat ping only fires if the job succeeds. If it runs twice, if it fails, or if it doesn't run at all — you'll know.
Related Guides
Related Resources
- Cron Overlap Checker — Check if your cron jobs overlap
- Cron Timezone Issues — Fix DST and timezone problems
- Cron Expression Validator — Verify your cron expression syntax
- Common Cron Schedules — Copy-paste ready cron expressions
Never debug silent cron failures again
CronSignal alerts you the moment a job doesn't run — or runs too often. Know about failures before they become disasters.
Sign up with Google3 monitors free. No credit card required.
Related Troubleshooting Guides
Need help with cron expressions? Use our cron validator to check syntax or cron generator to build expressions visually.