
A command can succeed in your terminal because that shell already has the right executable search path, working directory and configuration. A scheduled invocation need not have the same context. Making the executable path absolute solves only one of those dependencies.
A 2012 Server Fault canonical troubleshooting question provides the broader problem statement. We narrowed it to three execution-context differences, checked the Linux manuals and ran six controlled cases. We did not run cron or reproduce every reason a scheduled job can fail.
input_missing; absolute paths without a required configuration label returned label_missing. Two explicit-context variants succeeded. These are synthetic child-shell tests, not a scheduler reliability test.First separate dispatch from execution
Before changing the job, establish whether the scheduler invoked it. Check the intended account, installed entry and the scheduler's available logs or captured job output. A missing run and an invoked command that fails are different problems. Our experiment starts at invocation: it cannot diagnose an invalid schedule, a stopped daemon or the wrong account's crontab.
- Locate the executable. Check the interpreter and command the job actually uses. The Linux environment manual describes PATH as a list searched for an executable named without a slash. A custom tools directory in one shell's PATH is not evidence that another invocation has it.
- Locate the input. An absolute executable can still open
./payload.txtrelative to the process's current directory. Make the required directory deliberate or use the application's supported absolute input paths. - Identify required configuration. Declare the job's needed non-secret settings and use its supported mechanism for secrets. A terminal's exported variable is not proof that the scheduler's child receives it.
The cited crontab manual documents environment settings and a default SHELL of /bin/sh for that implementation. Check your installed cron's manual rather than assuming every scheduler uses an identical PATH, directory or startup sequence. Our minimal PATH below is an experiment setting, not a measured cron default.
Six cases, with one dependency exposed at a time
The November 7, 2026 run used Linux 6.8.0-147-generic, Python 3.12.3 and /bin/sh, resolving to dash. A new fixture contains an executable named lab-job, an application directory with a one-line payload, and a neutral directory. The application and tools directory names include spaces.
Every child receives an explicit environment containing only PATH and, when specified, LLAB_JOB_LABEL=demo. This is a non-secret synthetic label. The worker reads the payload, checks the label and emits one fixed line; it does not send messages, access an application database or perform a backup.
| Case | What changed | Exit | Observed output |
|---|---|---|---|
| Manual-style baseline | Tools on PATH, application directory, label supplied | 0 | Expected payload and label |
| Tools missing from PATH | Keep the directory and label; PATH is /usr/bin:/bin | 127 | lab-job: not found |
| Absolute executable, relative input | Neutral directory; label supplied | 20 | input_missing |
| Absolute executable and input | Neutral directory; required label omitted | 21 | label_missing |
| Absolute paths plus label | Neutral directory; all required inputs explicit | 0 | Expected payload and label |
| Explicit cd, PATH and label | Start neutral, then set context for the command | 0 | Expected payload and label |
The exit sequence was 0, 127, 20, 21, 0, 0. Each case checks the exit, stdout and stderr: 18 expectations passed. Exit codes 20 and 21 are deliberately assigned by this worker, not universal cron errors. Even 127 needs context: inspect the accompanying diagnostic rather than assuming every occurrence proves the same root cause.
The baseline is a constructed manual-style context, not a recording of an interactive login shell. Failures did not depend on a real cron daemon: we deliberately changed the command's inputs and observed the resulting failure stage.
Make the context part of the job
One successful fixture uses absolute paths for both the executable and its input, plus its non-secret label. The following illustrates that pattern; the /srv/example... files are placeholders, not installed files or a command to paste into a live job:
LLAB_JOB_LABEL=demo \
'/srv/example tools/lab-job' \
'/srv/example job/payload.txt'
The other successful fixture explicitly changes directory and supplies a scoped PATH and label. This keeps a relative input deliberate:
cd '/srv/example job' &&
PATH='/srv/example tools:/usr/bin:/bin' \
LLAB_JOB_LABEL=demo \
lab-job
The quoted paths preserve spaces. The && prevents the command from running after a failed directory change. These examples show the command portion of a proposed job, not a complete crontab entry. Adapt the actual interpreter, paths, settings, account and output handling to your application, then rehearse without real side effects before enabling its schedule.
Record only the small set of diagnostic values you need. Avoid dumping an entire environment into logs or public troubleshooting posts; it can contain credentials. Importing a whole personal shell profile is also a broader dependency than declaring the particular settings this job needs.
Run the isolated drill
Download and inspect the complete Python script. Use Linux with Python 3.9 or later, its standard library and /bin/sh:
python3 job_context_demo.py --out ./context-drill
Each run creates a new job-context-... child directory, worker and synthetic input. It refuses the drill if lab-job already exists on the minimal system PATH, so the missing-command control cannot run somebody else's program. Each shell call has a five-second timeout. The script has no input option for an existing job, makes no network calls, does not install a schedule and does not delete files.
Read the generated result.json. Each case records its constructed environment, working directory, command, exit and both output streams. Fixture-root paths are normalized to <fixture>; the recorded environments are allowlists, not dumps of the host's environment. Compare the dated Lab result with the expected outcomes. Durations describe these tiny commands on one host, not a performance benchmark or timing guarantee.
What still needs a separate check
A corrected execution context does not establish correct scheduling, permissions, application behavior or recovery. We did not test cron dispatch, PAM or login setup, timezone rules, permissions failures, containers, external credentials or a real service's job. Do not change the job to run as root merely because this synthetic example succeeded.
Once a harmless rehearsal runs in the intended context, use the manual acceptance sequence and blank run record to define success and failure. If the next invocation can overlap, choose a deliberate skip, wait or bounded-wait policy. If a response is missing, reconcile the effect before retrying. Those are separate questions from finding the executable and input file.
Sources and reproducible files
- Server Fault: canonical cron troubleshooting question — historical problem statement, verified via the public Stack Exchange API.
- crontab(5): environment settings and command format
- environ(7): process environments and PATH
- Isolated six-case script and recorded result