You’ve written a script. You test it manually: ./my-script.sh — works perfectly. You add it to cron, wait for the scheduled time… nothing happens. No output, no errors, just silence.
This is one of the most frustrating debugging experiences in Linux. Let’s fix it.
The Core Problem: Cron Runs in a Different Environment
When you run a script manually, you’re running it in your interactive shell with:
- Your
PATHvariable (with all your custom directories) - Your environment variables (loaded from
.bashrc,.profile, etc.) - Your current working directory
- Your user’s full shell configuration
Cron runs scripts in a minimal environment with almost none of this. That’s the root cause of nearly every “works manually, fails in cron” issue.
Cause 1: PATH Doesn’t Include Your Commands
The most common culprit. Your script calls aws, docker, python3, or some other command that lives in /usr/local/bin or another directory that’s in your interactive PATH but not in cron’s PATH.
Cron’s default PATH is typically: /usr/bin:/bin
Diagnosis:
| |
Fix — Option 1: Use absolute paths in your script
| |
Fix — Option 2: Set PATH in crontab
| |
Fix — Option 3: Set PATH in the script itself
| |
Cause 2: Missing Environment Variables
Your script relies on AWS_PROFILE, DATABASE_URL, API_KEY, or other environment variables that are set in your .bashrc but don’t exist in cron’s environment.
Diagnosis:
| |
You’ll likely see a very sparse environment compared to your interactive shell.
Fix — Source your environment in the script:
| |
Fix — Set variables in crontab:
| |
Cause 3: Working Directory Assumptions
Your script assumes it’s running from a specific directory. Maybe it reads ./config.yaml or writes to ./output/.
Cron runs from your home directory by default — not from where the script lives.
Diagnosis:
| |
Fix — cd to the script’s directory:
| |
Cause 4: No Display / TTY
Scripts that use GUI tools, open browsers, or expect user input will fail in cron. There’s no terminal attached.
Common offenders:
openorxdg-opencommands- Anything that prompts for input
- GUI applications
notify-sendwithout proper DBUS setup
Fix: Make your script fully non-interactive. Use flags like --yes, --quiet, or --non-interactive where available.
Cause 5: Output Goes Nowhere
Cron emails output to the system mail (if configured). If mail isn’t set up, output vanishes. Including errors.
Fix — Redirect output to a log file:
| |
The 2>&1 captures both stdout and stderr.
Fix — Add MAILTO in crontab:
| |
Cause 6: Permission Issues
The cron daemon runs your job, but maybe the script isn’t executable, or it tries to write somewhere the cron user can’t access.
Fix:
| |
The Nuclear Option: Debug Wrapper
When you can’t figure it out, wrap your script to capture everything:
| |
Run this wrapper from cron instead. You’ll get complete visibility into what’s happening.
Quick Checklist
When your cron job fails silently:
- ☐ Add
>> /tmp/myjob.log 2>&1to capture output - ☐ Use absolute paths for all commands
- ☐ Set PATH at the top of your script or crontab
- ☐ Source required environment variables
- ☐
cdto the script’s directory if using relative paths - ☐ Check the script is executable (
chmod +x) - ☐ Check
/var/log/syslogor/var/log/cronfor cron errors - ☐ Verify the crontab syntax with crontab.guru
The pattern that never fails: make your script self-contained. Set its own PATH, cd to its own directory, source its own environment. Assume nothing from the outside world.