-
Notifications
You must be signed in to change notification settings - Fork 1
Retries and Timeouts
Retry behaviour is not configurable from the manifest. There are no retries, retrywait or
timeout keys in this build; the numbers below are compiled in. Only MSI installs retry at
all, and only one type of item gets the aggressive policy. This page gives the exact figures
and what a failure does to the rest of the run.
Two policies, chosen per item:
| Installer helper | Everything else | |
|---|---|---|
| Attempts | 10 | 5 |
| Wait between attempts | 15 seconds | 10 seconds |
| Retries on | Any non-zero exit code | Only 1603, 1619, 1620, 1612
|
An item gets the first policy when its name contains System Binary Installer or
sbin-installer, or when its filename contains sbin-installer, all case-insensitively. Those
items log CRITICAL PACKAGE: {name} - using aggressive retry strategy on entry, and on
exhaustion fail with
CRITICAL: {name} failed with exit code {n} after {a} attempts. System cannot continue without this package. Everything else fails with MSI installer failed with exit code: {n}.
A retry logs at Warning: MSI error {code}, retrying in {n} seconds... (attempt {a}/{max}).
Nothing else retries. A ps1, exe, nupkg or pkg item that exits non-zero fails on the
first attempt. Downloads do not retry either — one GET per item, and a non-success status fails
the item immediately with Download failed: {StatusCode}.
Exit code 1618, ERROR_INSTALL_ALREADY_RUNNING, is not treated as a failure. Another installer
— during the Enrollment Status Page (ESP) this is usually the Intune Management Extension —
held the global Windows Installer transaction.
Before every launch attempt, BootstrapMate waits on Global\_MSIExecute for up to 600 seconds,
polling every 2 seconds. If the wait times out it launches anyway and logs
Windows Installer still busy after 600s; launching anyway (a 1618 will be retried, not failed).
If the launch does come back 1618, the run increments a collision counter, waits for idle
again, sleeps 3 seconds, and then decrements the attempt counter so the collision costs
nothing from the retry budget. The line is written at log level Debug:
MSI already running (1618) - waiting for the active installer to finish, then retrying (collision {n}, not counted as a failed attempt).
The cap is 30 collisions. Exceeding it throws
MSI installer for {name} could not start: another Windows Installer transaction held the system across {n} collisions. With the 600-second idle wait in front of each attempt, an item
stuck behind a genuinely wedged installer can therefore occupy the run for a long time before
that cap is reached.
Two supporting details. The idle wait treats a mutex it cannot open — absent, ACL-denied or
abandoned — as idle and returns immediately, so a permissions quirk never blocks a bootstrap;
the 3-second backoff exists because that early return would otherwise spin straight through all
30 collisions. And if msiexec.exe cannot be started at all, that is logged
(Failed to start msiexec.exe (Process.Start returned null); backing off and retrying) and
does consume an attempt, so a persistent launch failure cannot loop forever. That path has a
sharp edge: exhausting the attempts through launch failures alone leaves the retry loop without
raising an error, and the item is then reported as installed. Every ordinary failure raises
inside the loop, so this is narrow — but it is another reason not to treat a success line as
proof. See Troubleshooting and Gotchas.
| Operation | Limit |
|---|---|
| Manifest and package downloads | 100 seconds, the .NET default |
| Waiting for an installer or script to exit | None |
| Windows Installer idle wait, per attempt | 600 seconds |
| Run-summary POST to the reporting endpoint | 15 seconds |
| Waiting for another BootstrapMate instance | 30 minutes |
where.exe lookups for Chocolatey and sbin-installer |
5 seconds |
choco --version health check |
5 seconds |
choco cache clear during --force cleanup |
10 seconds |
Named pipe connect for --pipe
|
5 seconds |
The NetworkTimeout setting is configurable through the registry, policy and the graphical
app, and is not applied to the CLI's downloads. Treat the 100-second figure as fixed.
The second row matters most. Once an installer or script is launched, BootstrapMate waits for
it to exit with no time limit at all, so a hung installer hangs the entire run. There is no
donotwait equivalent, and no way to launch an item and move on.
If a second BootstrapMate starts while one is running, it waits on a global mutex, logging
Another BootstrapMate instance is already running - waiting for it to finish. After 30
minutes it gives up with
Timed out after 30 minutes waiting for another BootstrapMate instance to finish and exits 1.
An item failure is caught, logged as Failed to install package {name}: {message}, marked
failed in the progress dialog, and stepped over. The next item runs. The failed names are
carried to the end of the run: the phase finishes as Failed with ExitCode 1 and the names
in LastError, LastRunVersion is not written, and the run summary reports success: false.
The process still exits 0.
So the exit code is not a package-health signal, though everything else is. To judge a run,
count Failed to install package lines in the log, read the phase Stage, or check whether
C:\ProgramData\ManagedBootstrap\cache is empty — a cached file is kept only when its install
failed.
The exceptions, where the run does stop and exit 1, are failures outside the item loop: the
manifest cannot be downloaded or parsed, or no manifest URL can be resolved at all. Those mark
the phase Failed in the registry with the exception message in LastError.
There is no reboot handling and no resume: /norestart is passed to every MSI, nothing detects
a pending reboot, and no state is carried between runs beyond the registry status. The real
retry mechanism for a failed item is the next run — the MSI registers a BootstrapMate Self-Heal scheduled task that re-runs the whole manifest daily at 03:00 as SYSTEM, and items
that already succeeded are installed again.
The macOS build differs here: it retries downloads per item with manifest-settable retries
and retrywait keys, and supports donotwait. See
https://github.com/bootstrapmate/bootstrapmate-macintosh/wiki/Retries-and-Timeouts.