Cron Job Not Running? 10 Fixes for Common Cron Issues

2026/05/16
Cron Job Not Running? 10 Fixes for Common Cron Issues

Your cron job is not running because of one (or more) of these issues: the PATH environment is too minimal, your script lacks execute permission, you used relative paths, the shebang line is missing, or the cron daemon itself is not active. The fastest way to confirm whether cron even attempted your job is to check the system log with grep CRON /var/log/syslog | tail -20. If your job does not appear there, cron never tried to run it — the problem is in crontab configuration. If it does appear but your expected output is missing, the script itself is failing silently.

This guide walks through the 10 most common reasons cron jobs fail with concrete fixes for each. If you are new to cron, start with What Is a Cron Job? for fundamentals, or review Crontab Syntax Explained to verify your schedule expression.


Fix 1: PATH Not Set (Cron’s Minimal Environment)

Symptom: Your script runs perfectly from the terminal but produces “command not found” errors under cron, or simply does nothing.

Root Cause: When you open a terminal, your shell loads ~/.bashrc, ~/.bash_profile, or ~/.zshrc, which typically sets PATH to include /usr/local/bin, /opt/homebrew/bin, custom directories, and more. Cron does none of this. Its default PATH is extremely limited:

PATH=/usr/bin:/bin

Any command that lives outside those two directories — node, python3, docker, aws, kubectl — will fail with “command not found.”

Fix: Explicitly set PATH at the top of your crontab:

# Edit your crontab
crontab -e

# Add PATH as the first line
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

# Your jobs below
0 3 * * * /home/user/scripts/backup.sh

Alternatively, use absolute paths for every command inside your script:

/usr/local/bin/node /home/user/app/cleanup.js
/usr/bin/python3 /home/user/scripts/report.py

To discover the full path of any command, use which:

which python3
# /usr/local/bin/python3

Fix 2: Missing Execute Permission

Symptom: The cron log shows the job was triggered, but nothing happens. Running the script manually with bash script.sh works, but cron silently fails.

Root Cause: Cron attempts to execute the script directly (like ./script.sh), not by passing it to an interpreter. Without the execute bit set, the operating system refuses to run the file.

Fix: Add execute permission to your script:

chmod +x /home/user/scripts/backup.sh

Verify the permission:

ls -la /home/user/scripts/backup.sh
# -rwxr-xr-x 1 user user 1024 May 16 backup.sh

The x in the permission string confirms execute access. Make sure the user running the cron job (check with whoami or crontab -l) has execute permission on the file.


Fix 3: Wrong or Relative Paths in Script

Symptom: The script works when you cd into its directory and run it, but fails under cron. Files that should be created or read are missing.

Root Cause: Cron does not run your job from the script’s directory. It typically runs from the user’s home directory (or /). Any relative path like ./data/output.csv or ../config/settings.json resolves to the wrong location.

Fix: Use absolute paths for every file reference in your script:

#!/bin/bash

# Bad - relative paths
cd data
cat input.txt > output.csv

# Good - absolute paths
DATA_DIR="/home/user/project/data"
cat "$DATA_DIR/input.txt" > "$DATA_DIR/output.csv"

If your script must run from a specific directory, add an explicit cd with error handling at the top:

#!/bin/bash
cd /home/user/project || exit 1
# Now relative paths work correctly
./process.sh

Fix 4: Missing Shebang Line

Symptom: The script executes without errors in your terminal using bash script.sh or python3 script.py, but cron produces garbled output or “exec format error” in logs.

Root Cause: Without a shebang (#!) on the first line, the system does not know which interpreter to use. Some systems default to /bin/sh (which is often dash, not bash), causing bash-specific syntax like arrays, [[, or $(()) to fail. Python scripts without a shebang may be interpreted as shell commands entirely.

Fix: Always include the correct shebang as the very first line:

For Bash scripts:

#!/bin/bash
set -euo pipefail

echo "Backup starting at $(date)"

For Python scripts:

#!/usr/bin/env python3

import sys
print("Running report generation")

For Perl scripts:

#!/usr/bin/perl
use strict;
use warnings;

After adding the shebang, ensure the file also has execute permission (Fix 2).


Fix 5: Environment Variables Not Available

Symptom: Your script relies on environment variables like DATABASE_URL, API_KEY, or AWS_PROFILE that are set in your shell profile, but under cron these variables are empty.

Root Cause: Cron does not source ~/.bashrc, ~/.profile, or any shell initialization file. The only environment variables available are: HOME, LOGNAME, PATH (minimal), and SHELL. Everything else is undefined.

Fix: Option A — Define variables directly in the crontab:

crontab -e

# Set variables at the top
DATABASE_URL=postgres://localhost:5432/mydb
API_KEY=sk-abc123
PATH=/usr/local/bin:/usr/bin:/bin

0 * * * * /home/user/scripts/sync.sh

Option B — Source your profile at the start of the cron command:

0 * * * * . /home/user/.env && /home/user/scripts/sync.sh

Option C — Load variables inside the script itself:

#!/bin/bash
source /home/user/project/.env
# Variables are now available
echo "Connecting to $DATABASE_URL"

Fix 6: Cron Daemon Not Running

Symptom: No cron jobs run at all — not just yours, but system-wide cron jobs are also failing. Nothing appears in /var/log/syslog for CRON.

Root Cause: The cron daemon (crond or cron) is not running. This can happen after a system update, in Docker containers (where cron is not started by default), or if someone manually stopped the service.

Fix: Check and start the cron service:

# Debian/Ubuntu
sudo systemctl status cron
sudo systemctl start cron
sudo systemctl enable cron  # Start on boot

# CentOS/RHEL/Fedora
sudo systemctl status crond
sudo systemctl start crond
sudo systemctl enable crond

For Docker containers, cron is typically not running by default. Add it to your entrypoint:

# In Dockerfile or entrypoint script
RUN apt-get update && apt-get install -y cron
CMD cron && tail -f /var/log/cron.log

Verify cron is running:

ps aux | grep cron
# root  1234  0.0  0.0  /usr/sbin/cron -f

Fix 7: Syntax Error in Crontab Expression

Symptom: Your specific job never fires, but other cron jobs work fine. No errors appear in the log for your entry.

Root Cause: The crontab time expression contains a syntax mistake. Common errors include: using 6 fields instead of 5, confusing day-of-week numbering (0 or 7 = Sunday), using unsupported named shortcuts, or placing a comment on the same line as a job.

Fix: Validate your crontab syntax. The five fields are:

┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-7, Sun=0 or 7)
│ │ │ │ │
* * * * * /path/to/command

Common mistakes and corrections:

# WRONG: 6 fields (seconds are not supported in standard cron)
0 0 3 * * * /path/to/script.sh

# CORRECT: 5 fields
0 3 * * * /path/to/script.sh

# WRONG: inline comment breaks the command
0 3 * * * /path/to/script.sh # daily backup

# CORRECT: comment on its own line
# Daily backup
0 3 * * * /path/to/script.sh

Use crontab -e to edit — it validates syntax before saving. For detailed syntax reference, see Crontab Syntax Explained.


Fix 8: Output Not Redirected (Mailbox Full / Mail Not Configured)

Symptom: The job ran successfully in the past but suddenly stopped. Or the job runs but you see “mail delivery failed” messages in system logs.

Root Cause: By default, cron emails all output (stdout and stderr) from your command to the user. If the mail system is not configured (common on modern servers), or the mailbox is full, cron may throttle or skip subsequent runs. Additionally, without output redirection, you lose all debugging information.

Fix: Always redirect output explicitly:

# Redirect both stdout and stderr to a log file
0 3 * * * /home/user/scripts/backup.sh >> /var/log/backup.log 2>&1

# Discard output entirely (if you don't need it)
0 3 * * * /home/user/scripts/backup.sh > /dev/null 2>&1

# Send only errors to a log file
0 3 * * * /home/user/scripts/backup.sh > /dev/null 2>> /var/log/backup-errors.log

To disable cron mail entirely, add MAILTO="" at the top of your crontab:

crontab -e

MAILTO=""
0 3 * * * /home/user/scripts/backup.sh >> /tmp/backup.log 2>&1

Fix 9: User Not Allowed to Use Cron (cron.allow / cron.deny)

Symptom: Running crontab -e returns “You (username) are not allowed to use this program” or your jobs simply never execute despite correct configuration.

Root Cause: Linux uses two files to control cron access: /etc/cron.allow and /etc/cron.deny. If cron.allow exists, only users listed in that file can use cron (whitelist mode). If cron.allow does not exist, users in cron.deny are blocked. If neither file exists, access rules depend on the distribution (some allow all users, some deny all non-root users).

Fix: Check and modify access files:

# Check if your user is denied
cat /etc/cron.deny
# If your username is listed, remove it

# Check if an allow list exists (whitelist mode)
cat /etc/cron.allow
# If this file exists, your user MUST be in it

# Add your user to the allow list
sudo sh -c 'echo "yourusername" >> /etc/cron.allow'

After modifying these files, verify access:

crontab -l
# Should show your crontab without permission errors

Note: On some systems, the cron service must be restarted after changing these files:

sudo systemctl restart cron

Fix 10: Script Has Windows Line Endings (\r\n)

Symptom: The script works perfectly on your local machine (or when run manually) but under cron you get errors like “/bin/bash^M: bad interpreter”, “command not found” with extra whitespace, or mysterious failures at seemingly valid lines.

Root Cause: If you edited the script on Windows or transferred it via certain methods, it may contain Windows-style line endings (\r\n — carriage return + line feed) instead of Unix line endings (\n — line feed only). The \r character is invisible in most editors but causes the shell to misinterpret commands, paths, and even the shebang line.

Fix: Convert the file to Unix line endings:

# Using dos2unix (install if needed: apt install dos2unix)
dos2unix /home/user/scripts/backup.sh

# Using sed
sed -i 's/\r$//' /home/user/scripts/backup.sh

# Using tr
tr -d '\r' < /home/user/scripts/backup.sh > /tmp/fixed.sh
mv /tmp/fixed.sh /home/user/scripts/backup.sh
chmod +x /home/user/scripts/backup.sh

To detect if a file has Windows line endings:

# Shows ^M at end of lines if Windows format
cat -A /home/user/scripts/backup.sh | head -5

# Or use file command
file /home/user/scripts/backup.sh
# "ASCII text, with CRLF line terminators" means Windows format

Prevent future issues by configuring your editor and Git:

# Git: auto-convert to LF on commit
git config --global core.autocrlf input

Quick Diagnosis Checklist

When your cron job fails, run through this checklist systematically:

CheckCommandWhat to look for
Cron daemon running?systemctl status cronActive (running)
Job in crontab?crontab -lYour entry listed
Cron attempted it?grep CRON /var/log/syslog | tail -20Your command in log
Syntax valid?crontab -e (validates on save)No errors on save
Script executable?ls -la /path/to/script.shx in permissions
Shebang present?head -1 /path/to/script.shStarts with #!
Unix line endings?file /path/to/script.shNo “CRLF” mention
PATH sufficient?env -i PATH=/usr/bin:/bin which yourcommandPath resolved
User allowed?crontab -l (no permission error)Shows entries
Env vars set?Check script or crontab headerVariables defined

The single best debugging technique is to simulate cron’s environment locally:

env -i PATH=/usr/bin:/bin HOME=$HOME SHELL=/bin/bash /bin/bash /path/to/your/script.sh

This strips all environment variables and runs your script in the same minimal context cron uses. If it fails here, it will fail in cron — and you will see the exact error message.

For a comprehensive overview of scheduling concepts, revisit What Is a Cron Job?. To validate your time expressions, see Crontab Syntax Explained.

B
BenZ Software Developer

Software developer passionate about technology. Sharing programming experiences and learning notes.