Skip to content

Retries and Timeouts

Rod Christiansen edited this page Sep 3, 2026 · 1 revision

Retries and Timeouts

Two manifest keys control retry behaviour — retries and retrywait — and both apply to downloads only. Everything else is either a fixed timeout in the code or no timeout at all. This page states which is which, because the difference decides whether a bad item costs you thirty seconds or an unbounded wait.

Retries apply to downloads, and nothing else

retries is the total number of download attempts for an item's payload, not the number of extra tries after the first. The default is 3. After each attempt the file's SHA-256 is recomputed and compared against hash; a match ends the loop, anything else counts as a failed attempt.

retrywait is the number of seconds slept between attempts. The default is 5. The sleep also runs after the final failed attempt, so an item that never succeeds costs retries × retrywait seconds of sleeping in addition to the transfer time — with the defaults, about 15 seconds of waiting before the item is given up on.

Both keys accept an integer or a string containing one, so 3 and "3" both decode.

A failing download logs one line per attempt and then a final line:

Hash mismatch or download failed for /Library/Application Support/BootstrapMate/munkitools.pkg. Retrying in 5s...
All retries failed for /Library/Application Support/BootstrapMate/munkitools.pkg.

Because HTTP status codes are not inspected, a 404 or an authentication failure reaches you as a hash mismatch on this path rather than as an HTTP error.

Nothing else is retried. A package whose installer run exits non-zero fails immediately. A script that exits non-zero fails immediately. A manifest that fails to download or decode ends the run with exit 1 without a second attempt. If you need an operation retried, put the retry inside the script.

The timeouts that exist

None of these are settable from the manifest — there is no per-item timeout key.

Wait Limit On expiry
Manifest download 60 s Run exits 1
One item download attempt 120 s Counts as a failed attempt; the retry loop continues
Network availability at startup --network-timeout, default 120 s Logged, run continues anyway
Data volume writable 30 s Logged, run continues anyway
Waiting for management configuration 300 s Logged; without a manifest URL the run then exits 1
Run-summary POST to reportingUrl 15 s request, 20 s overall Logged only; never fails the run

The startup network wait is the only one with a knob, and only from the command line: a networkTimeout set by configuration profile is read but not used. See Preferences.

The waits that have no timeout

  • A package install. /usr/sbin/installer is waited on with no ceiling. A package that hangs hangs the run.
  • A synchronous script. A rootscript or userscript without donotwait is waited on with no ceiling. An interactive prompt, a read, or a network call with no timeout of its own will stall provisioning indefinitely, and because there is no console it will never be answered.
  • Waiting for a user session. The userland stage polls every two seconds for a console user and will wait forever. A Mac that enrols and is never logged into stays in this state with the dialog showing "Waiting for user to log in...".

There is no watchdog and no overall run deadline. A hung item is a hung run: every later item and stage waits behind it, the LaunchDaemon is never torn down, and no run summary is reported. Recovering means killing the process on the machine.

Script authors should build their own limits — wrap slow calls, and never wait on input.

donotwait

donotwait: true on a script is the one way to keep a long-running item from blocking the rest of the run. The script is launched, the item is recorded as a success as soon as the process starts, and BootstrapMate moves straight on. Its exit code is never read and its output is not captured, so it can neither fail the run nor tell you anything. It has no effect on package items.

Fire-and-forget children survive BootstrapMate's teardown, which is what makes donotwait the right tool for starting the ongoing management run — see Handoff to Munki — and the wrong tool for anything whose result you need to know.

What a failing item does to the rest of the run

  • A preflight script that fails to download or launch stops everything: setupassistant and userland are both skipped and the run exits 1.
  • A setupassistant or userland item that fails is recorded, and the stage carries on with the next item. Both stages run to the end. The run's final exit code is 1, and the dialog closes on "Setup completed with errors".
  • Any failure means the success-only steps are skipped: a requested --reboot does not happen unless the run succeeded.

Either way, cleanup still runs — the one-shot LaunchDaemon removes itself even after a failed run, so a failure does not leave the bootstrap armed to retry at next boot.

See also

Clone this wiki locally