Bash error: no such job
Bash "no such job" errors come from job-control commands (fg/bg/wait/kill %1) when no matching background job exists in the current shell.
Error String
bash: fg: no such job
Tldr
Job control (`%1`, `%+`, `%foo`) only works on jobs started by the current shell. Scripts run with the default settings have job control off; subshells can't see the parent's jobs. Use PIDs and `wait $pid` for portable background-process control.
Cause
Scripts often try `wait %1` after a background command — works interactively, fails in non-interactive shells where job control is disabled.
Repro
#!/usr/bin/env bash
sleep 1 &
wait %1 # bash: wait: %1: no such jobFix
#!/usr/bin/env bash
sleep 1 &
pid=$!
wait "$pid"
echo "exit: $?"Explanation
Capture `$!` immediately after starting the background job. Keep PIDs in an array when you have several: `pids+=($!)`, then `wait "${pids[@]}"`.
Faq
Q
Why does %1 work in my terminal but not in the script?
A
Interactive shells enable job control automatically; non-interactive shells do not. The same command therefore resolves a job spec in your terminal and fails inside the script.
Q
How do I wait for several background jobs and still catch failures?
A
Collect each `$!` into an array, then loop over it running `wait "$pid" || failed=1`. A bare `wait` waits for everything but discards the individual exit statuses.
Deep Dive
Heading
Job control is per-shell, and scripts usually have it off
Body
Job numbers such as %1 belong to the shell instance that started the job. A non-interactive script does not enable job control by default, so `fg`, `bg`, `%1` and `jobs` either report nothing or fail with "no such job". Background processes started with `&` inside a script are still tracked, but you address them by PID from `$!`, not by job spec. If you genuinely need job specs in a script you must turn job control on explicitly with `set -m`, and even then the jobs disappear as soon as the subshell that owns them exits.
Heading
Use PIDs and wait instead
Body
The portable pattern is to capture `$!` right after launching each background command and pass those PIDs to `wait`. `wait "$pid"` returns that job exit status, so you can fail the script when any worker failed. `kill "$pid"` stops it. Because a PID is a plain number it survives being stored in an array, passed to a function, or written to a file — none of which is true of a job spec. A job that has already been reaped also produces this error, so check that you are not waiting on the same job twice.
Checklist
Run `jobs` immediately before the failing command to see what the shell actually tracks.
Replace `%1` style references with a PID captured from `$!`.
Confirm the job was not already reaped by an earlier `wait`.
If you truly need job control in a script, add `set -m` near the top.