Few Linux problems are as annoying as this one: you run your script, it works perfectly, you add it to cron, and then nothing happens. No backup, no report, no clear error. The script has not changed, so why does it fail only when the schedule runs it?
The answer is almost never the script itself. Cron runs your job in a very different environment from your interactive terminal. Paths are shorter, folders are different, and none of your personal settings are loaded. In this guide you will work through the causes in a sensible order, fix each one, and learn how to see the exact error cron has been hiding from you.
Quick Answer
A cron job that works manually but fails on schedule usually fails because cron uses a minimal environment: a short PATH, a different working folder, and no shell profile. Fix it by using full paths to every command and file, setting PATH at the top of your crontab or script, and redirecting output to a log file with >> ~/cron.log 2>&1 so you can read the real error.
Why Cron Is Not Like Your Terminal
When you open a terminal, your shell reads startup files that set your PATH, your aliases, your language settings, and sometimes keys or tokens your scripts rely on. Cron does none of that. It starts your job with a small, plain environment designed for predictability, not comfort.
That difference explains the classic pattern. Your terminal knows that python3 lives in a local folder, or that a tool sits in /usr/local/bin. Cron may only search /usr/bin and /bin. Your terminal starts in your home folder. Cron may start somewhere else, so a relative path that worked for you points at nothing for cron.
Once you accept that cron is a different room rather than a broken tool, the fixes become logical. You are not repairing the script; you are making the script describe everything it needs, instead of assuming your terminal already provided it.
Step 1: Capture the Real Error in a Log
Guessing wastes time, so get evidence first. Edit your crontab with crontab -e and add output redirection to the end of your job line, like this: 0 2 * * 0 /home/yourname/scripts/backup.sh >> /home/yourname/cron.log 2>&1. The first part saves normal output, and the 2>&1 part saves error messages into the same file.
- Add the redirection to the job line and save the crontab.
- Temporarily change the schedule to run in two or three minutes from now, so you do not wait a week for a test.
- Wait for the job to run, then open the log with
cat ~/cron.log. - Read the exact error message. It will usually name the missing command or file directly.
- Fix the cause, test again, and restore the real schedule when it passes.
This one habit turns a mystery into a short task. The crontab manual page explains how cron handles output and environment, and it is worth reading once you have your first log in front of you.
Step 2: Replace Short Names With Full Paths
The most common cause is a command cron cannot find. In your terminal, typing rsync works because your PATH includes its folder. Under cron, that same word may return command not found.
Find the Full Path of Each Command
In your terminal, run which rsync, which python3, or which followed by any command your script uses. The terminal prints the full path, such as /usr/bin/rsync. Use those full paths inside your script, or set a proper PATH at the top of the script like this: PATH=/usr/local/bin:/usr/bin:/bin.
Do the same for files. Replace backup.sh with /home/yourname/scripts/backup.sh in the crontab, and replace relative paths inside the script, such as ./data or reports/today.txt, with full paths from the root of the system. Relative paths depend on the starting folder, and cron does not promise to start where you expect.
Step 3: Check Permissions and the Executable Bit
Your script may run in the terminal because you start it with bash script.sh, which hides a missing permission. Cron usually starts the file directly, so it needs execute permission. Run chmod +x /home/yourname/scripts/backup.sh and make sure the first line of the script is a proper shebang such as #!/bin/bash.
Also check who owns the crontab and what the script needs to reach. A job in your personal crontab runs as you, but a job in the root crontab or in /etc/crontab runs as a different user with different permissions. If your script reads files only your user can open, keep the job in your own crontab. If it writes to a protected folder, that write will fail under your account no matter how well it seemed to work in a sudo terminal session.
Step 4: Look for Interactive Assumptions
Some scripts quietly depend on a human being present. They ask a question, wait for a password, need an unlocked key, or expect a graphical session. Cron has no keyboard and no screen, so anything that waits for input will hang or fail.
- Remove prompts, or pass answers as options such as
-ywhere the tool supports it safely. - Do not rely on
sudoinside a scheduled script unless you have configured it carefully, because sudo may demand a password. - Avoid commands that need your desktop session, such as tools that open windows or use your logged-in keyring.
- Give network tools full options for unattended use, for example
ssh -o BatchMode=yes, so they fail clearly instead of waiting forever for a password.
Environment variables are another hidden assumption. If your script uses a variable that your profile normally sets, define it inside the script or at the top of the crontab. Our guide on setting up a cron job for a Sunday 2 AM backup shows a clean crontab layout that avoids most of these traps from the start.
Step 5: Test in a Cron-Like Environment
After fixing the obvious causes, test the way cron will actually run the job. The command env -i /bin/bash /home/yourname/scripts/backup.sh starts the script with an empty environment, which is close to what cron provides. If the script survives that test, it will almost certainly survive cron.
You can also schedule a harmless test job one minute ahead that writes the date to a file: * * * * * date >> ~/cron-test.log. If that file appears, cron itself is alive and the problem is inside your job. If it does not appear, check the service with systemctl status cron and review the system log with grep CRON /var/log/syslog on Ubuntu or Debian. The Ubuntu cron guide explains service checks and log locations for common distributions.
Common Mistakes and Useful Tips
- Editing the wrong crontab. Jobs added with
sudo crontab -ebelong to root, not to you. Use plaincrontab -efor personal jobs. - Percent signs in commands. In a crontab, an unescaped
%is treated as a newline. Escape it as\%, which matters in date formats such asdate +\%F. - No newline at the end of the file. Some cron versions ignore a final line that does not end with a newline. Press Enter after your last job line.
- Wrong day or time fields. A swapped hour and minute can schedule a job monthly instead of daily. Read the five fields slowly before saving.
- Assuming the machine was on. Cron skips jobs while the computer is off or asleep. Check uptime before blaming the script.
- Debugging without a log. Always redirect output first. One real error message is worth an hour of guessing.
Conclusion
When a job runs manually but fails under cron, think environment, not bad luck. Capture the error in a log, use full paths everywhere, set PATH yourself, check permissions, and remove anything that expects a person at a keyboard. Work through those steps in order and nearly every scheduled job starts behaving. Keep the log redirection in place afterwards, so if the job ever fails again, it will tell you why.
Frequently Asked Questions
Why does cron say command not found when the command works for me?
Because cron searches a much shorter PATH than your terminal. Find the full location with which in your terminal, then use that full path in the script or set PATH at the top of the script.
How can I see errors from a cron job?
Add >> /home/yourname/cron.log 2>&1 to the end of the job line. After the job runs, read that file. It will contain the normal output and the error messages together.
Does cron run my shell profile or .bashrc file?
No. Cron starts with a minimal environment and does not load your profile. Set every variable your script needs inside the script itself or at the top of the crontab.
Why did my job not run at all last night?
The computer may have been off or asleep, the cron service may be stopped, or the schedule fields may not mean what you expected. Check the service status, the system log, and each of the five time fields.
Should I put my job in /etc/crontab instead?
Only for system-wide jobs that must run as a specific user. Personal jobs belong in your own crontab, which you edit with crontab -e. The system crontab also has an extra user field, so lines are not interchangeable.


Leave a Reply