WinRE Manager returns one of four exit codes. Orchestration should treat them as distinct outcomes, not as success/failure booleans.
| Code | Name | Meaning |
|---|---|---|
0 |
EXIT_SUCCESS |
WinRE enabled, dedicated recovery partition healthy, state file written or already current. |
1 |
EXIT_REBOOT_REQUIRED |
Deployment succeeded; a reboot is required to complete WinRE registration. |
2 |
EXIT_WARNING |
WinRE functional but degraded, or the run deferred work, or a non-fatal failure is queued for retry. Details in the log. |
3 |
EXIT_FATAL |
Deployment aborted. No state written, or state file deleted. Investigate the log. |
When a run’s outcome satisfies more than one condition, the priority order is:
EXIT_FATAL > EXIT_REBOOT_REQUIRED > EXIT_WARNING > EXIT_SUCCESS
EXIT_FATAL always wins. Between EXIT_REBOOT_REQUIRED and EXIT_WARNING, reboot-required wins — the machine needs to reboot either way.
In practice only two combinations are reachable through the final exit-code determination:
1 — whether or not a warning flag was also set, because the reboot is the action the operator must take either way.$Script:nonFatalWarning = $true bullet below). Returns 2.Some exit paths bypass the final determination and exit EXIT_WARNING or EXIT_FATAL directly — the v47 strip-failure abort, the Step 3 → Step 4 pipeline gate, the Audit Mode deferral, the VMD-query-indeterminate deferral, the OS-fallback BitLocker deferral, the v45 pre-shrink deferral (including the v47 race-detector abort reason), the Step 5 race-detector abort, the enable-only target-preparation failure, the enable-failure counter exit, the concurrent-instance deferral, the offline-fallback deferral, the v48 architecture-gate refusal, the v48 elevation-guard refusal, the v48 intervening-anchor surplus rejection, the v48 multi-intervening rejection, the v48 offline LocalInputsId mismatch, and the loop-breaker. Those cases are described in the sections below.
EXIT_SUCCESS (0)The fast path found nothing to do and exited cleanly. Or the full-update path completed, WinRE reports Enabled, the state file was written, and no warning flags were set.
Also returned by -DryRun when the dry run completes without errors. Dry runs do not write a state file; they exit 0 from the deployment step.
EXIT_REBOOT_REQUIRED (1)reagentc /enable returned exit 0 but reagentc /info did not immediately report Enabled. This is a common result after a fresh registration: Windows schedules the registration to complete on the next reboot.
The script writes the state file with PendingReboot = true, records the deployed partition number and disk number so the next run knows where the WIM is, and exits with code 1.
Also returned by the pending-reboot path when the retry reagentc /enable still returns reboot-required, and by the enable-only path when reagentc /enable returns reboot-required.
EXIT_WARNING (2)Reached when any of the following is true at exit time:
OS-fallback. The dedicated recovery partition could not be created and WinRE is deployed to C:\Recovery\WindowsRE.
Strip-failure abort (v47). Step 3’s strip stage (Remove-AllThirdPartyDrivers) rejected the candidate. Every failure mode of the strip — initial Get-WindowsDriver enumeration failure, re-enumeration failure at any iteration, a missing Driver field on an enumeration entry, Remove-WindowsDriver failure for any entry, iteration-budget exhaustion without reaching zero, or a final enumeration that returns a non-zero count — exits EXIT_WARNING immediately, before injection is attempted, before export, before any partition work, and before any reagentc call. The log line is Strip stage failed - candidate rejected. Dismounting with -Discard and deferring before injection, export, partition work, or WinRE disable. The abort branch dismounts the mounted image with -Discard, removes the mount directory, sets the checkpoint back to Step=2, removes base.wim and any stale winre_optimized.wim, and exits. The machine is left unchanged: no partition touched, no WIM deployed, WinRE not disabled, no state file written. Enumeration failure is never interpreted as zero drivers — a candidate that cannot be proven clean is discarded rather than deployed. This is the v47 addition and it is the first gate of Step 3.
Base-WIM copy-integrity check rejected the candidate (v47 patch 2). After Copy-Item in Step 2, the destination base.wim is hashed and compared to the source-selection SourceHash. A mismatch or an unreadable destination rejects the candidate: base.wim is removed, the checkpoint is reset to Step=2, and the run exits EXIT_WARNING. The check exists because the Step 3 and Step 4 checkpoints bind to the source hash; without it, a checkpoint could record a hash that did not describe the bytes that actually entered servicing. The log line is Base WIM copy hash mismatch: source=..., copied=... - rejecting candidate or Base WIM copy is unreadable after Copy-Item - rejecting candidate. The machine is unchanged: no WIM deployed, no partition touched, WinRE not disabled. Investigate whether the source changed during acquisition - the same class of race the pre-/disable race detector catches later.
Architecture-gate refusal (v48 patch 1). The startup architecture check refuses to run on any architecture other than x64. The token is derived from PROCESSOR_ARCHITECTURE with PROCESSOR_ARCHITEW6432 taking precedence when present; Win32_OperatingSystem.OSArchitecture is consulted only as a 32-bit-OS fallback. ARM64, x86, and any architecture whose token cannot be resolved produce Unsupported OS architecture '<arch>': this manager supports x64 only. No WinRE, partition, image, checkpoint, or recovery-state changes have been made. and exit EXIT_WARNING before the manifest fetch, the OEM pack resolution, the DesiredStateId computation, or any state-modifying action. The machine is unchanged: no partition touched, no WIM deployed, WinRE not disabled, no state file written. This is a stable deferral — any machine whose architecture is not x64 will continue to exit 2 on every run until the manager adds support or the machine is replaced. ARM64 support is not claimed; a future fleet requirement would be a separate, tested change.
Intervening-anchor surplus rejection (v48 patch 1). The intervening-anchor plan (the C: | D: | Recovery layout) rejects with intervening anchor is N MiB smaller than the plan requires to seat the recovery partition at the disk tail; this v48 scope does not extend the anchor (BitLocker). Manual intervention: extend the anchor to close the gap, or reduce the desired recovery partition size, then re-run. when the recovery partition being reclaimed is larger than the new bucket size, i.e. when the anchor’s current end is farther from the disk tail than the plan needs. The v48 scope does not extend the anchor; a BitLocker-encrypted anchor is not safely growable via Resize-Partition alone, and the invariants forbid additional manage-bde work on the anchor. The run defers with the old recovery route preserved, no partition touched. The operator path: extend the anchor to close the gap, or reduce the desired recovery partition size, then delete C:\Recovery\OEM\winre_state.json and C:\Recovery\OEM\winre_partition_deferred.json to force a retry.
Multi-intervening rejection (v48 patch 1). A C: | D: | E: | Recovery layout — two or more non-recovery partitions between C: and the type-coded recovery cluster — still rejects, as it did under v47. The v48 message names the intervening partitions with Format-PartitionRef enrichment: recovery-typed partitions exist beyond the intervening anchor's recovery cluster; this layout is not supported (intervening: disk N part M, ...). The old recovery partition is intact; no partition was touched. This is the same stable deferral as v47; automating multi-intervening handling is a v49 candidate.
Offline LocalInputsId mismatch (v48 patch 1). When the driver manifest fetch fails and the state file indicates a full update is needed, the offline fallback engages. If the state file was written by v48 or later and the current locally-computable inputs hash differs from the stored LocalInputsId, the run defers with Offline fallback: stored LocalInputsId <hash> does not match the current locally-computable inputs <hash>. A hardware or OS input changed while the machine was offline; the stored DesiredStateId no longer describes this machine. rather than trusting a stored DesiredStateId that describes a machine whose hardware or OS has since changed. The machine is unchanged; the next run with network recomputes the DSI and either converges or defers normally.
Step 3 → Step 4 pipeline gate (v44 patch 1). OEM or VMD injection failed ($Script:ImageInjectionComplete = $false). The script exits with EXIT_WARNING immediately after Step 3, before Step 4 (dism /Export-Image), before Step 5 (partition work), before Step 6 (deployment), and before any reagentc call. The pipeline sets the checkpoint back to 2 so the next run re-acquires the base WIM from source and re-runs injection against a clean WIM. The state-write gate alone would not have prevented the deployment of a WIM with no OEM or VMD drivers; the pipeline gate closes that gap. On a VMD-based system the resulting WinRE cannot see the OS disk at all, so this exit is a protective failure, not a degraded-success. The winre_optimized.wim from the run is removed by the gate before exiting, and as of v44 patch 3 the abort branch also removes base.wim from WorkDir so the next run’s Step 2 can rename cleanly. Under v47 this gate is reached only if the strip stage succeeded — a strip failure exits via the strip-failure abort above, and the pipeline gate is not reached. The two paths have the same exit code, the same checkpoint rollback, and the same disk-state outcome; the difference is that the injection-failure gate has already captured the pre-injection third-party driver count and has already attempted Add-WindowsDriver.
Audit Mode / OOBE / sysprep deferral (v43 patch 5, further revision). The startup guard reads HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\State → ImageState before any other action. When the value is present and is not IMAGE_STATE_COMPLETE, Windows is in a transitional state (Audit Mode, OOBE, sysprep generalize, or sysprep specialize) where reagentc /enable is blocked with ERROR_CANCELLED (0x4c7, 1223) regardless of WIM correctness or the state of the recovery partition. The run logs a clear message naming the ImageState value and defers before the hardware check, the manifest fetch, the OEM pack resolution, the DesiredStateId computation, or any state-modifying action. The machine is left unchanged: no partition touched, no WIM deployed, WinRE not disabled, no state file written, checkpoint file preserved. Under -DryRun the gate performs the same read-only classification and logs Would defer … without exiting. This is the highest-priority deferral — it runs before every other gate.
VMD-query-indeterminate deferral (v44 patch 6). The VMD hardware presence check is fail-closed. The query wraps Get-PnpDevice -PresentOnly in -ErrorVariable and treats any enumeration error as an indeterminate result, not as “VMD hardware absent”. On an indeterminate result the correct driver set cannot be determined: proceeding might select a driver set that omits the VMD package on a machine that has VMD hardware, and the resulting WinRE would not see the OS disk. The run logs the enumeration error, sets $Script:nonFatalWarning = $true, removes the checkpoint file, and exits EXIT_WARNING before committing any state. No WIM is deployed, no partition is touched, no reagentc call is made. The next run retries the enumeration; a transient PnP service issue is the most likely cause. See troubleshooting.md.
OS-fallback BitLocker deferral (v43 patch 5, further revision 5). On the OS-fallback route — reached when dedicated-partition creation fails and the script falls back to C:\Recovery\WindowsRE — the target volume is the OS volume. reagentc refuses to enable WinRE on an encrypted OS volume, always. The OS-fallback gate checks C: via Test-VolumeEncrypted -MountPoint "C:" before deploying the WIM and defers with EXIT_WARNING unless the classifier returns exactly $false (confirmed fully decrypted). The script never modifies C:’s BitLocker state — decrypting the OS volume is hours of I/O, changes the recovery key relationship, and the OS volume is the user’s data. The machine is left unchanged: no WIM deployed, no reagentc call made, no state file written, checkpoint file preserved. The log message names the classifier result and the resolution: complete decryption of C: (manage-bde -off C:), or wait for an in-progress decryption to finish. The log message explicitly states that completing encryption, adding a recovery-password protector, or enabling protection do not satisfy the FullyDecrypted requirement — those actions make C: more protected, not less. Under -DryRun the gate logs the deferral and continues. Note that this gate is only reached on the OS-fallback route; the enable-only and dedicated-partition routes never depend on C:’s BitLocker state, because their target volume is the recovery partition.
Registered-source fingerprint abort at the Ensure-AdequateRecoveryPartition site (v47). The race detector captured the registered WinRE image’s location, version, and WIM SHA256 at the start of the rebuild, then re-read them immediately before the /disable that Ensure-AdequateRecoveryPartition would perform. If any of the three changed — typically because Windows Update serviced or replaced the registered image during candidate preparation — the abort fires before /disable. The function restores C: to its captured size via Restore-OSPartitionSize, invalidates the checkpoint back to Step=2, removes base.wim and any stale winre_optimized.wim, and returns Deferred with Reason = "registered source changed before disable". The main flow exits EXIT_WARNING. Because the abort fires before /disable, WinRE is still Enabled and registered to its original location, no partition has been deleted, and the recovery route is intact. The log lines are Registered WinRE source changed during candidate preparation - aborting before /disable. Restoring C: to its captured size; no partitions have been deleted. followed by Dedicated replacement deferred before partition deletion (registered source changed before disable). The existing WinRE route was preserved; not attempting OS-fallback. This is a race detector, not a lock — the microseconds between the final re-read and /disable returning cannot be closed without moving the re-read inside the disable→enable window and violating Rule 3. The detector narrows the exposure window from minutes to that residual. See architecture.md — “The v47 rebuild pipeline” — “The pre-/disable race detector”.
Registered-source fingerprint abort at the Step 5 deployment site (v47). The same race detector, invoked at the other /disable site. When Ensure-AdequateRecoveryPartition did not run (the existing recovery partition was reusable), the first /disable of the execution is the one in the Step 5 deployment path. The recheck runs immediately before it. If any of location, version, or WIM hash has changed since capture, the run invalidates the checkpoint back to Step=2, removes base.wim and any stale winre_optimized.wim, sets $Script:nonFatalWarning = $true, and exits EXIT_WARNING. The log line is Registered WinRE source changed during candidate preparation - aborting before /disable. The old WinRE route remains intact; no partition changes have been made at this site. Because this abort fires before /disable, WinRE is still Enabled, no partition was touched, and the recovery route is intact. Only one of the two race-detector sites fires per execution — whichever /disable the run reaches first — so there is exactly one recheck per rebuild.
Dedicated recovery partition creation deferred before partition deletion (v45 patch 1; v46 patch 2 added two reasons; v47 added one). Ensure-AdequateRecoveryPartition runs a read-only geometry plan and, when the plan calls for a C: shrink, performs the shrink in the reversible window — before reagentc /disable and before any partition deletion. Any of the following conditions causes the function to return Deferred and the main flow to exit EXIT_WARNING with the old recovery route preserved:
Get-PartitionSupportedSize or the disk-layout enumeration failed. RetrySuppressible = $false; the deferral marker is not written.RetrySuppressible = $false; the deferral marker is not written.Get-Volume -DriveLetter C returned nothing. Fail-closed: the script refuses to shrink without verifying the 3 GiB reserve. RetrySuppressible = $false; the deferral marker is not written. The read failure may be transient.RetrySuppressible = $true; the deferral marker is written.RetrySuppressible = $true; the deferral marker is written.RetrySuppressible = $true; the deferral marker is written.RetrySuppressible = $true; the deferral marker is written.reagentc /disable returned non-zero, or the subsequent status check did not report Disabled. RetrySuppressible = $false; the deferral marker is not written. The run attempted Restore-PreviousWinRERoute first; the Deferred result is returned only when the previous route was confirmed restored.Enabled but Resolve-WinRELocationToPartition returned nothing for the registered location, or reagentc reports no registered location at all. Delete-last ordering and route restoration both depend on identifying which partition is active; without it, no partition is protected and a mid-loop failure could leave the machine with no working recovery route. As of v48 patch 1 the guard fires ahead of the pre-shrink and ahead of reagentc /disable, so the machine is left with WinRE still Enabled and the old recovery partition intact. RetrySuppressible = $false; the deferral marker is not written./disable race detector aborted. See the dedicated case above. RetrySuppressible = $false; the deferral marker is not written. The abort restores C: to its captured size, invalidates the checkpoint back to Step=2, and removes base.wim and any stale winre_optimized.wim. C: is verified at its original size before the Deferred result is returned — if Restore-OSPartitionSize failed, the state file is deleted so the next run retries from clean.Restore-PreviousWinRERoute confirmed the previous route is still functional (the active partition is deleted last, so it remained available). RetrySuppressible = $false; the deferral marker is not written. As of v46 patch 2, the two restores are reported separately. When Restore-OSPartitionSize verified C: at its original size, the reason is recorded as recovery partition deletion failed; previous route restored. When the resize target could not be verified at its original size, the reason is recorded as recovery partition deletion failed; previous route restored but <resize-target label> geometry restore unverified (the label is OS partition (C:) on the non-intervening path and anchor partition (disk X part Y) on the intervening-anchor path; v48 patch 1) and $Script:GeometryRestoreFailed is set — the state file is invalidated so the next run retries from clean.In every case the old recovery partition remains and no partition was deleted; the run did not attempt OS-fallback. The state file is left unchanged. For every reason, WinRE stays Enabled and registered to the old recovery partition.
active WinRE location could not be resolved). As of v48 patch 1 this guard fires ahead of the pre-shrink and ahead of reagentc /disable, so the machine is left with WinRE still Enabled and the old recovery partition intact; the pre-v48-patch-1 placement (after /disable) is no longer the current behavior. See troubleshooting.md for the reason-specific resolutions.The v47 patch 1 race-detector abort (registered source changed before disable) fires before /disable but after the pre-shrink, so C: is restored to its captured size and the old WinRE route remains intact and Enabled. Because this abort returns RetrySuppressible = $false, no sidecar is written for this reason. The general deferral-marker mechanism (write, honor, clear) is described in the Dedicated recovery partition creation deferred before partition deletion bullet above and does not apply here; the next run re-evaluates source selection from the top. See troubleshooting.md for the reason-specific resolutions.
Enable-only target-preparation failure (v43 patch 5, further revision 5). The enable-only path prepares the target recovery partition via Set-RecoveryPartitionReadyForWinRE before calling reagentc /setreimage. If the helper reports that the target could not be made unencrypted within its 300-second timeout, the enable-only path records the failure, increments the state file’s EnableFailureAttempts counter, writes LastEnableResult = "failed", removes the checkpoint file, and exits EXIT_WARNING. The deployment is already current; the next run will retry enable-only. After three consecutive failures the loop-breaker fires and the next exit is EXIT_FATAL (see below).
Enable-failure counter (v43 patch 5, further revision). The enable-only path called reagentc /enable on a deployment that was already current. The call returned a terminal failure — either a generic "failed" result or a "bitlocker" result (reagentc refused because the target volume is BitLocker-protected, even after the helper prepared it). The enable-only path increments the state file’s EnableFailureAttempts counter, writes LastEnableResult to the corresponding value, removes the checkpoint file, and exits with EXIT_WARNING. It does not fall through to full update: the deployment is current, and rebuilding it would not change the outcome of the enable step. The next run will retry the enable-only path (not the full-update path). After three consecutive terminal failures the loop-breaker fires and the next exit is EXIT_FATAL (see below). Both "failed" and "bitlocker" count toward the same three-failure threshold; they are not distinguished by the counter.
Concurrent-instance deferral (v44 patch 4). A second WinRE.ps1 process was launched while another instance was already running. The program lock at C:\ProgramData\OEM\Logs\WinREManager.lock is held exclusively by the first instance (FileShare.None via [System.IO.File]::Open), and the second instance cannot acquire it. The second instance logs Another WinRE Manager instance is already running (program lock file is exclusively held). Exiting without making any changes. This is not a deployment failure - the other instance is doing the work and will complete on its own. … and exits EXIT_WARNING immediately, before the Audit Mode guard, before the hardware check, and before any state-modifying action. The state file is not read, not written, and not modified; the checkpoint file is untouched. The lock is not acquired under -DryRun, so a concurrent dry run is not affected. As of v44 patch 4 this failure shape replaces the pre-patch-4 rename error at C:\Temp\WinREWork\winre.wim, which was reported as EXIT_FATAL (code 3). The rename error is still reachable in the narrow case where the lock acquisition fails for a reason other than contention — a permission error, a missing Logs directory, or a transient filesystem issue — in which case the script logs Could not set up program lock at <path> : <error> - proceeding without single-instance protection; concurrent runs may collide and continues unprotected. See the EXIT_FATAL section for that narrow case.
Offline-fallback deferral (v44 patch 5). The driver manifest fetch failed after its retry budget (typically a DNS failure, a proxy block, or a total network outage), and the state file was present and parseable but the fast path did not fire — meaning the state file indicates a full update is needed (stale DSI, force-upgrade, driver-version drift, missing or unreadable metadata anchor, or a locally-detected input change). A full update requires the live manifest to resolve the driver set, which is unavailable. The run logs Offline fallback: the machine requires a full update (state file is stale or unhealthy), but the driver manifest is unavailable. Cannot proceed without a live manifest. Will retry on the next scheduled run when the network is available. and exits EXIT_WARNING without touching the machine. No WIM is deployed, no partition is touched, WinRE is not disabled, no state file is written or modified, checkpoint file preserved. If the state file’s fast-path checks do pass, the offline run does not exit with this message — it takes the fast path and exits EXIT_WARNING because $Script:offlineFallback = $true (see the “Fast path under offline fallback” case below). If there is no state file at all, the run throws and exits EXIT_FATAL (code 3) — a first deployment on a machine with no state file requires the live manifest. The offline fallback and its residual risk are documented in state-and-idempotency.md and architecture.md.
Fast path under offline fallback (v44 patch 5; metadata-based as of v47). A special case of the offline-fallback deferral. When the manifest fetch fails and the state file is present and its local safety checks pass (WinRE Enabled, exactly one type-coded recovery partition on the OS disk, and — as of v47 — a DeployedWinREMetadata anchor in the state file whose Version|SPBuild matches the currently-registered image’s servicing metadata), the script takes the fast path successfully but still exits EXIT_WARNING because $Script:offlineFallback = $true is set. The v46-and-earlier deployed-WIM-hash-vs-CurrentImageHash comparison no longer gates the offline fast path; it was retired in v47 in favour of the metadata comparison. A state file written by v46 or earlier has no anchor and forces a rebuild on the first v47 run regardless of network state. From the second v47 run onward the offline check is metadata-based. The log shows the offline-fallback engage line (Driver manifest unavailable - taking the offline fallback path using the state file's stored DesiredStateId ...), followed by Offline fallback: skipping OEM pack resolution (network unavailable), Offline fallback: skipping VMD detection (manifest unavailable), Offline fallback: skipping required-driver resolution, Offline fallback: using state file's stored DesiredStateId <id>, WinRE status: Enabled, Location: ..., Version: ..., State file accepted (DesiredStateId match), Operating mode: DEDICATED (WinRE on dedicated recovery partition), Released program lock. Exit code 2. Total runtime under 90 seconds. The machine is unchanged. The next scheduled run with network performs a full manifest fetch, detects any hardware drift that occurred while offline, and either takes the fast path (if no drift) or forces a rebuild (if drift).
$Script:nonFatalWarning = $true. Set by a range of non-fatal conditions the run encountered: Restore-OSPartitionSize failure on any post-shrink geometry-restore path, Remove-OrphanPartition orphan survival, Remove-StrayRecoveryPartitions cleanup failure, Set-RecoveryPartitionAttributes failure at the end of Step 6, the full-update post-enable "failed" and "bitlocker" outcomes, OEM map resolution failure for a supported vendor, Set-RecoveryPartitionReadyForWinRE failure on any deferring path, the OS-fallback BitLocker gate, the v44 patch 4 lock-acquisition failure, the v44 patch 6 VMD-query-indeterminate deferral, the v45 patch 1 post-delete extension safe fallback, and the v47 pre-injection discrepancy check (when the filtered pre-injection third-party count is non-zero despite a successful strip). Fallback copy denial (ACL) sets the warning flag as of v48 patch 2; the earlier behavior (logged without affecting the exit code) was corrected because a machine with a degraded LKG copy would otherwise exit EXIT_SUCCESS while its next-run fallback safety was compromised — the denial remains non-fatal to the deployment itself but the run now exits EXIT_WARNING, consistent with the exit-code discipline.
Post-delete extension safe fallback (v45 patch 1; ceiling-fill in v47 patch 2). When the plan calls for C: to grow into the space the old recovery partitions occupied, Invoke-OSPartitionExtend runs after the deletions. If all three extension attempts fail, the safe fallback creates the recovery partition at the current (un-extended) C: end, sized to min(AvailableSize, 2 GiB) — the full available extent, capped at the managed-recovery ceiling — sets $Script:nonFatalWarning = $true, and continues with WinRE deployable. Sizing to the ceiling fills the extent in the common case (the surplus after a failed extension is typically a few hundred MiB, well under the ceiling), eliminating the trailing unallocated extent. Only when the surplus exceeds 2 GiB does a trailing extent remain, and it is logged explicitly. The end state is DEDICATED, but the exit code is EXIT_WARNING because of the warning flag. Exact geometry is a goal, not a reason to leave WinRE disabled. If the space available after the current C: end is smaller than the plan’s bucket size, the script restores C: to its original size and returns $null; the main flow falls through to the OS-fallback decision, which either succeeds (state file written with UsedOSFallback = true, exit EXIT_WARNING) or defers (OS-fallback BitLocker gate on encrypted C:, exit EXIT_WARNING).
$Script:UsedOSFallback = $true. Distinct from nonFatalWarning; can be true without any warning-level event, and is the deliberate outcome of the shrink-fails path.The warning code is returned on the fast path, the enable-only path, the pending-reboot success path, and the full-update path — anywhere a warning flag can be set. In every case the state file is still written (or left in place) if the run reached a state-write point. The v47 strip-failure abort, the Step 3 → Step 4 pipeline gate, the Audit Mode deferral, the VMD-query-indeterminate deferral, the OS-fallback BitLocker deferral, the v45 pre-shrink deferral (including the v47 race-detector reason), the Step 5 race-detector abort, the v44 patch 4 concurrent-instance deferral, and the v44 patch 5 offline-fallback deferral all exit before the state-write point, so any existing state file is left unchanged and no new state is committed. The enable-only failure and the enable-failure counter exit do reach a state-write point and update the state file. The v45 post-delete extension safe fallback reaches the state-write point and writes the state file with the fallback geometry.
Important for orchestration: the table below enumerates sixteen distinct exit-code-2 outcomes, and they require different actions. The bulleted list above this paragraph describes the underlying conditions in more detail; some bullets map to a single table row and a few do not appear as their own row. The state file’s LastUpdated timestamp, the presence of the UsedOSFallback flag, the presence of the deferral marker at C:\Recovery\OEM\winre_partition_deferred.json, and the specific log content distinguish them.
| Case | State file LastUpdated |
Log signature | Action |
|---|---|---|---|
| OS-fallback | Newer than the run start (state file written this run, with UsedOSFallback = true) |
Dedicated recovery partition creation failed after all attempts. banner |
The machine ended in OS-fallback. Do not reboot or intervene. Route to a soft-failure queue if your deployment policy requires dedicated partitions. |
| Strip-failure abort (v47) | Unchanged, or state file absent | Strip stage failed - candidate rejected. Dismounting with -Discard and deferring before injection, export, partition work, or WinRE disable. |
The strip stage could not normalize the mounted image to zero third-party drivers. The WIM was not deployed, the partition was not touched, and WinRE was not disabled. The checkpoint was set back to 2, and base.wim and any stale winre_optimized.wim were removed. The next run will retry from step 2 and re-acquire the source. Investigate the specific strip failure reason (enumeration, removal, missing INF field, or budget exhaustion) in the log lines immediately preceding the abort. |
| Base-WIM copy-integrity check (v47 patch 2) | Unchanged, or state file absent | Base WIM copy hash mismatch: source=..., copied=... - rejecting candidate or Base WIM copy is unreadable after Copy-Item - rejecting candidate |
The candidate base.wim did not match the selected source’s SHA256, or the copied file could not be re-read. The candidate is removed, the checkpoint is reset to Step 2, and the run exits EXIT_WARNING. Investigate whether the source changed during acquisition. |
| Step 3 → Step 4 pipeline gate | Unchanged, or state file absent | Image injection did not complete. Stopping before Step 4 and before any deployment. |
The OEM or VMD injection failed after a successful strip. The WIM was not deployed, the partition was not touched, and WinRE was not disabled. The checkpoint was set back to 2. The next run will retry from step 2. Investigate the injection failure reason (OEM pack download, extraction, INF validation, or VMD driver download). |
| Audit Mode deferral | Unchanged, or state file absent | Deferring WinRE Manager: Windows is not in a normal-running state (Setup\State\ImageState=…) |
The machine has not finished OOBE, or is in Audit Mode or a sysprep phase. No partition work was attempted. Complete OOBE, sign in to a normal desktop session, and re-run. Do not retry immediately. |
| VMD query indeterminate (v44 patch 6) | Unchanged, or state file absent | VMD hardware detection reported N error(s) during PnP enumeration: … followed by VMD hardware detection was indeterminate; deferring because the driver set cannot be safely determined. |
A PnP enumeration error prevented the VMD hardware presence check from completing. The correct driver set cannot be determined, so the run defers rather than guessing. No WIM was deployed, no partition was touched, no reagentc call was made. Resolve the PnP service issue (Windows device management, an antivirus/EDR product blocking device enumeration, a device in an error state) and re-run. |
| OS-fallback BitLocker deferral | Unchanged, or state file absent | OS-fallback deferred: C: could not be confirmed fully decrypted (Test-VolumeEncrypted=…) followed by the operator guidance line |
The dedicated partition could not be created and the OS-fallback target (C:) is not confirmed fully decrypted. No WIM was deployed, no reagentc call was made. Wait for C: to reach FullyDecrypted (or complete decryption of C: with manage-bde -off C:), then re-run. Do not retry immediately — the same gate will fire. |
| Pre-shrink deferral (v45 patch 1; v46 patch 2 added reasons; v47 added the race-detector reason) | Unchanged, or state file absent | Dedicated replacement deferred before partition deletion (<Reason>). The existing WinRE route was preserved; not attempting OS-fallback. |
The destructive replacement was deferred before any partition was deleted. The old recovery partition is still present and WinRE is still registered to it; as of v48 patch 1, all deferral reasons leave the machine with WinRE still Enabled (the pre-deletion resolver guard was moved ahead of the pre-shrink and ahead of /disable). The <Reason> names the specific constraint. If the reason is registered source changed before disable, the abort was the v47 race detector catching a Windows Update servicing event during candidate preparation; simply re-run — the source is now stable, and the next run will re-select the source and prepare a fresh candidate. If the reason is any other, free space on C:, defragment, correct the disk layout, or address the oversized partition. After resolving, delete C:\Recovery\OEM\winre_partition_deferred.json (and, if you also want to clear the deployment identity, C:\Recovery\OEM\winre_state.json) to force a retry. See troubleshooting.md for the reason-specific resolutions. |
| Registered-source fingerprint abort at Step 5 (v47) | Unchanged, or state file absent | Registered WinRE source changed during candidate preparation - aborting before /disable. The old WinRE route remains intact; no partition changes have been made at this site. |
The v47 race detector caught a Windows Update servicing event during candidate preparation, at the Step 5 /disable site. WinRE is still Enabled, no partition was touched, no WIM was deployed. The checkpoint was set back to 2, and base.wim and any stale winre_optimized.wim were removed. Simply re-run — the next run will re-select the source and prepare a fresh candidate based on the newly-registered image. This is not a failure; it is the design’s intended response to a source that changed mid-preparation. |
| Enable-only failure (counter < 3) | Newer than the run start (state file written this run, with LastEnableResult set to "failed" or "bitlocker" and the counter incremented) |
One of: Enable-only /enable failed (attempt N of 3).; Enable-only /enable refused with the BitLocker error after the target partition was confirmed unencrypted (attempt N of 3).; Enable-only path: target recovery partition could not be made unencrypted - deferring without further changes (target-preparation failure). |
The deployment is current; only the enable step failed. Do not rebuild. Investigate the enable failure itself (ReAgent.xml corruption, missing registration, a Windows component problem, an antivirus product holding the recovery partition open). The next run will retry enable-only. After three consecutive failures the loop-breaker fires and the next run exits with code 3. |
| Concurrent-instance deferral (v44 patch 4) | Unchanged, or state file absent | Another WinRE Manager instance is already running (program lock file is exclusively held). |
Not a failure. The other instance is doing the work and will complete on its own. Do not investigate the log for a deployment problem, do not retry, do not intervene. If your orchestration treats exit 2 as a soft failure and re-queues the remediation, be aware that the re-queue will also exit 2 until the first instance completes. Either wait, or disable the scheduled task before running a manual remediation. See deployment.md. |
| Offline-fallback deferral (v44 patch 5) | Unchanged, or state file absent | Offline fallback: the machine requires a full update (state file is stale or unhealthy), but the driver manifest is unavailable. |
The network was unavailable and the state file indicates a full update is needed. No operator action is required — the next scheduled run with network will complete the work. If the machine will be offline for a prolonged period and the deployment is stale, resolve the network issue or wait. If the log instead shows Offline fallback: using state file's stored DesiredStateId …, the fast path fired successfully and the exit is a degraded-success, not a deferral — the machine is healthy and unchanged. Do not treat it as a failure. |
| Architecture-gate refusal (v48 patch 1) | Unchanged, or state file absent | Unsupported OS architecture '<arch>': this manager supports x64 only. |
The startup architecture check refused. Expected on ARM64, x86, or machines whose architecture could not be resolved. No state was committed. This is a stable deferral: any machine whose architecture is not x64 will continue to exit 2 on every run until the manager adds support or the machine is replaced. Do not retry expecting a different result. |
| Intervening-anchor surplus rejection (v48 patch 1) | Unchanged, or state file absent | intervening anchor is N MiB smaller than the plan requires to seat the recovery partition at the disk tail; this v48 scope does not extend the anchor (BitLocker). |
The intervening-anchor layout (C: \| D: \| Recovery) had a surplus: the recovery partition being reclaimed is larger than the new bucket size, so the plan cannot seat the new recovery partition at the disk tail without extending the anchor. The v48 scope does not extend the anchor (BitLocker-encrypted anchors are not safely growable via Resize-Partition alone). The old recovery partition is intact; no partition was touched. Operator action: extend the anchor to close the gap, or reduce the desired recovery partition size, then delete C:\Recovery\OEM\winre_state.json and C:\Recovery\OEM\winre_partition_deferred.json to force a retry. |
| Multi-intervening rejection (v48 patch 1) | Unchanged, or state file absent | recovery-typed partitions exist beyond the intervening anchor's recovery cluster; this layout is not supported |
The layout has two or more non-recovery partitions between C: and the type-coded recovery cluster (C: \| D: \| E: \| Recovery). The v48 scope is deliberately narrow: exactly one intervening partition, no partition-moving. Same stable deferral as v47, but the v48 message names the intervening partitions via Format-PartitionRef. Automating multi-intervening handling is a v49 candidate. |
Offline LocalInputsId mismatch (v48 patch 1) |
Unchanged, or state file absent | Offline fallback: stored LocalInputsId <hash> does not match the current locally-computable inputs <hash>. |
The machine was offline and the state file’s stored LocalInputsId did not match the current machine’s locally-computable inputs (hardware identity, OS build, CPU vendor/generation). A hardware or OS input changed while the machine was offline; the stored DesiredStateId no longer describes this machine. The machine is unchanged. Operator action: bring the machine online so a fresh manifest can be fetched and a new DesiredStateId computed; the next scheduled run will do this automatically. |
The distinguishing factor between OS-fallback and the deferral/gate cases is the state file timestamp: OS-fallback reaches the state-write step and updates LastUpdated; the v47 strip-failure abort, the Step 3 → Step 4 pipeline gate, the Audit Mode deferral, the VMD-query-indeterminate deferral, the OS-fallback BitLocker deferral, the v45 pre-shrink deferral (including the v47 race-detector reason), the v47 Step 5 race-detector abort, the concurrent-instance deferral, and the offline-fallback deferral all exit before it and leave the timestamp unchanged. The enable-only failure also updates the state file, but its log signature is unique and cannot be confused with OS-fallback.
A partition-creation failure — with its Dedicated recovery partition creation failed after all attempts. banner — is only logged when the destructive attempt actually ran and failed. A deferral or a pipeline gate is not that.
EXIT_FATAL (3)Reached when any of the following occurs:
FATAL: WinRE Manager requires an elevated (Administrator) PowerShell session. Re-run from an elevated prompt, or launch via the scheduled task's SYSTEM context. No changes have been made to WinRE, partitions, BitLocker, drive letters, the workspace, or the state file. and exits EXIT_FATAL in milliseconds. On refusal the guard creates the log directory itself so its FATAL message has somewhere to be written; the guard runs before the program lock, before hardware probes, before the manifest fetch, and before any state-modifying action. The check accepts both interactive Administrator sessions and the SYSTEM context used by the scheduled task. Under -DryRun the guard still fires. This is a fail-fast refusal for the case the 2026-10-05 field log demonstrated: an unelevated launch would otherwise spend roughly four minutes on hardware detection, manifest fetch, and the GitHub base-WIM download before failing at Mount-WindowsImage.dism /Export-Image failed. Non-zero exit from DISM or missing output file.reagentc /disable failed at Step 5. WinRE is enabled and the script could not disable it, so the deployment cannot proceed.reagentc /setreimage failed at Step 6. Registration failed; the WIM was copied but the registry is inconsistent.Deploy-WimTransactional, which restores the previous WIM from the rollback copy in the workspace before returning failure. If the rollback restore itself succeeds, the machine is left with the previous WIM on the active route but the deployment did not complete; if the rollback restore fails, the target may be incomplete and manual recovery is required. The log distinguishes the two: Rollback copy restored to <path> confirms the restore; rollback restore hash verification failed or rollback restore failed names the failure. A failure with no rollback copy available (because the target had no previous WIM) leaves the target with no WIM, matching the pre-v48 failure shape.Set-RecoveryPartitionReadyForWinRE returned $false before the WIM was deployed. Under the v43 patch 5 (further revision 5) policy this is a fatal exit rather than a deferral on the full-update path. On the create path, Ensure-AdequateRecoveryPartition has already removed the old recovery route and WinRE is already disabled; deferring would leave the machine in a partial state and force a manual recovery. On the reuse path the previous route is still Enabled and a deferral would have been possible, but the policy treats the failure uniformly so the operator resolves the target’s BitLocker state before the WIM is deployed.Enabled but the location is empty. Same class.FATAL: WinRE is not enabled at exit. The final attempt to enable WinRE failed. On a machine where the recovery partition was lost, this is the pre-v43-patch-5 Device Encryption failure mode. See troubleshooting.md for the recovery procedure.C:\Recovery\OEM\winre_state.json. A first deployment requires a live manifest. The script logs Driver manifest unavailable and no state file exists - a live manifest is required for the first deployment on this machine. and throws. The outer catch logs FATAL ERROR: … and exits 3. A machine in this state will retry on the next scheduled run when the network is available. As of v44 patch 5.RepairAttempts > 3. The pending-reboot path has accumulated three failed repair attempts (RepairAttempts = 3 in the state file); the fourth pending-reboot run hits the FATAL guard at the start, before attempting the repair. Manual intervention is required.EnableFailureAttempts >= 3 with LastEnableResult set to "failed" or "bitlocker", and WinRE is still Disabled. The loop-breaker logs Refusing to retry reagentc /enable: it has failed on the last N consecutive runs and WinRE is still Disabled. Manual intervention is required., names the state file path, and exits EXIT_FATAL without attempting anything else. The state file is left in place so the operator can inspect it. The cause may be Audit Mode (though the Audit Mode startup guard would have deferred earlier), a broken ReAgent registration, a Windows component problem, a filesystem problem on the target partition, or an antivirus product holding the recovery partition open. Resolve the underlying cause, then delete C:\Recovery\OEM\winre_state.json to reset the counter and re-run. See the “Enable-only failure (counter < 3)” row above for the pre-loop state.winre.wim (v44 patch 4, narrow case). The pre-patch-4 concurrent-instance failure shape. As of patch 4 this is only reachable when the lock acquisition failed for a reason other than contention — a permission error, a missing Logs directory, or a transient filesystem issue — and the run proceeded unprotected. In that case a second instance can still collide at Step 2 and exit with Cannot rename because item at '<workspace>\winre.wim' does not exist. The script logs Could not set up program lock at <path> : <error> - proceeding without single-instance protection; concurrent runs may collide earlier in the log when this happens. If you see this fatal exit, check the log for the lock-acquisition failure line and investigate why the lock could not be acquired. See deployment.md for the lock design and troubleshooting.md for the recovery procedure.catch block logs and exits 3.Fatal exits do not write a state file. If a state file was written earlier in the run and the fatal exit occurs after that point, the state file is left as-is; on the next run, the fast path may fire if the state is now healthy, or the full-update path may re-run if it is not.
Special case for orchestration: exit code 3 with the log line FATAL: WinRE is not enabled at exit on a machine that no longer has a recovery partition indicates the pre-patch-5 failure mode. Do not retry automatically. Follow the recovery procedure in troubleshooting.md.
Second special case: exit code 3 with the log line Refusing to retry reagentc /enable indicates the enable-failure loop-breaker. Do not retry automatically — the same guard will fire on the next run because the state file still records the counter value. Resolve the underlying cause, delete the state file, and re-run. See troubleshooting.md for the diagnosis procedure.
Deferring WinRE Manager: Windows is not in a normal-running state (Setup\State\ImageState=…). The VMD-query-indeterminate gate logs VMD hardware detection was indeterminate; deferring because the driver set cannot be safely determined.. The OS-fallback BitLocker gate logs OS-fallback deferred: C: could not be confirmed fully decrypted (Test-VolumeEncrypted=…) followed by the resolution guidance. The v45 pre-shrink deferral logs Dedicated replacement deferred before partition deletion (<Reason>). and, when the marker is written, Recorded retry-suppressing deferral for DesiredStateId <id>; …. The v47 race-detector abort at the Ensure-AdequateRecoveryPartition site logs Registered WinRE source changed during candidate preparation - aborting before /disable. Restoring C: to its captured size; no partitions have been deleted.. The v47 race-detector abort at the Step 5 deployment site logs Registered WinRE source changed during candidate preparation - aborting before /disable. The old WinRE route remains intact; no partition changes have been made at this site.. The v47 strip-failure abort logs Strip stage failed - candidate rejected. Dismounting with -Discard and deferring before injection, export, partition work, or WinRE disable.. The concurrent-instance gate logs Another WinRE Manager instance is already running (program lock file is exclusively held). …. The offline-fallback gate logs Offline fallback: the machine requires a full update (state file is stale or unhealthy), but the driver manifest is unavailable. …. All nine, plus the four v48 deferral additions (the architecture-gate refusal, the intervening-anchor surplus rejection, the multi-intervening rejection, and the offline LocalInputsId mismatch), are distinguishable by the log text alone. The v48 elevation-guard refusal exits EXIT_FATAL (code 3), not EXIT_WARNING, and its log signature is described in the EXIT_FATAL section above. The state file’s LastUpdated timestamp distinguishes the exit-2 cases (unchanged, or absent) from OS-fallback and enable-only failure (both newer than the run start).Target partition X/Y (Z:) is BitLocker-managed (state=…) - running manage-bde -off to decrypt and a confirmation line with the elapsed time when the decryption completes. If Set-RecoveryPartitionReadyForWinRE returned without decrypting, the log records Target partition X/Y (Z:) is already unencrypted - reagentc /enable can proceed.EnableFailureAttempts from the state file, or look for the Enable-only /enable failed (attempt N of 3) or Enable-only /enable refused with the BitLocker error after the target partition was confirmed unencrypted (attempt N of 3) log line.C:\Recovery\OEM\winre_partition_deferred.json. Its DesiredStateId and Since fields tell you the exact DSI under which the destructive sequence deferred, and the timestamp records when. The marker is not part of the deployment identity, and its presence does not change the exit code — but it is the reason a subsequent run may exit EXIT_WARNING without re-attempting the pre-shrink.Acquired program lock at C:\ProgramData\OEM\Logs\WinREManager.lock when the lock was acquired, [DRY RUN] Skipping program lock - DryRun is read-only and safe to run concurrently with other instances under -DryRun, or Could not set up program lock at <path> : <error> - proceeding without single-instance protection; concurrent runs may collide when acquisition failed for a non-contention reason. If the third line is present, the run was vulnerable to the pre-patch-4 concurrent-instance collision for its entire duration.Strip: pre-strip third-party inventory: N package(s) followed by one line per package (Strip: <published INF> | <provider> | <version> | <original filename>), and then either Strip: image already has zero third-party drivers (no-op) or one Strip: removed <published INF> line per removal plus a final Strip: verified zero third-party drivers remaining after removing N package(s). The pre-strip inventory is the primary field-evidence mechanism for whether Windows Update ever delivers third-party driver packages inside a serviced WinRE image — see architecture.md — “The v47 rebuild pipeline” — “What the empirical observation settled”.Base WIM source selection: <reason> -> <path> on every full-update run. The reason names the branch: registered at least as new as LKG, registered older than LKG, metadata comparison indeterminate, no hash-validated LKG present, registered not usable, or GitHub cold-start./disable race detector rechecked the source, and what it found. The log records Captured registered-source fingerprint: location=<loc>, version=<ver>, hash=<hash> at the start of the rebuild, and one of the two recheck lines: Registered-source recheck at <site> : unchanged (location=<loc>, version=<ver>) on a clean recheck, or the abort line naming the changed field. The <site> is Ensure-AdequateRecoveryPartition or Step 5 deployment.For any of those details, read the log. See troubleshooting.md.
The pending-reboot path has its own exit logic. In order:
RepairAttempts is incremented before any other work. If the incremented value exceeds 3 (equivalently, the state file already records RepairAttempts >= 3), the run exits EXIT_FATAL immediately without attempting repair. This guard is a precondition on the whole pending-reboot path, not a post-condition on its outcome.DeployedDiskNumber / DeployedPartitionNumber, or C:\Recovery\WindowsRE for OS-fallback).Set-RecoveryPartitionReadyForWinRE on the recorded partition. If it returns $false — the target could not be made unencrypted within the timeout — defer with EXIT_WARNING immediately.Test-VolumeEncrypted. If it does not return exactly $false, defer with EXIT_WARNING immediately. The deferral logs Pending-reboot OS-fallback: C: could not be confirmed fully decrypted (Test-VolumeEncrypted=…) - deferring without changing C: BitLocker state. The script never modifies C:’s BitLocker state.reagentc /enable against the recorded path. If the retry succeeded and WinRE reports Enabled:
UsedOSFallback was carried over from the state file → EXIT_WARNING.nonFatalWarning was set → EXIT_WARNING.EXIT_SUCCESS.EXIT_REBOOT_REQUIRED.Note that PendingReboot and RepairAttempts are recorded in the state file before the exit, so a machine that exits with code 3 due to too many repair attempts still has a state file reflecting the current repair count.
The pending-reboot path writes the state file with LastEnableResult = "ok" and EnableFailureAttempts = 0. A machine that reaches the pending-reboot path therefore has its enable-failure counter reset regardless of the outcome — the pending-reboot path represents a different failure mode (registration did not complete after a reboot) and is tracked by the separate RepairAttempts counter. The two counters are independent. A target-preparation failure on the pending-reboot path does not increment EnableFailureAttempts; the exclusion is deliberate, because immediately after a reboot the target partition’s encryption state may be transiently indeterminate, and the pending-reboot path is tracked exclusively by RepairAttempts.
Recommended orchestration policy:
| Code | Action |
|---|---|
| 0 | Record success. No further action. |
| 1 | Schedule a reboot at the next maintenance window. The next run will finish the registration. |
| 2 | Investigate the log. Check the state file’s LastUpdated timestamp, the UsedOSFallback flag, and whether a deferral marker exists at C:\Recovery\OEM\winre_partition_deferred.json. Sixteen cases: (a) If the log shows the Dedicated recovery partition creation failed after all attempts. banner and the state file was updated this run with UsedOSFallback = true, the machine ended up in OS-fallback. Do not reboot or intervene while encryption is in progress. (b) If the log shows Strip stage failed - candidate rejected. Dismounting with -Discard and deferring before injection, export, partition work, or WinRE disable. and the state file was not updated, the v47 strip stage could not normalize the mounted image. No WIM was deployed, no partition touched, WinRE not disabled. The checkpoint was reset to 2. Investigate the specific strip failure reason in the log lines immediately preceding the abort (enumeration, removal, missing INF field, or budget exhaustion). The next run will retry from step 2 and re-acquire the source. (c) If the log shows Image injection did not complete. Stopping before Step 4 and before any deployment. and the state file was not updated, OEM or VMD injection failed after a successful strip. Same remediation as the pre-v47 case: no WIM was deployed, no partition touched, WinRE not disabled. The checkpoint was reset to 2. Investigate the injection failure reason. (d) If the log shows Deferring WinRE Manager: Windows is not in a normal-running state (Setup\State\ImageState=…) and the state file was not updated, the machine has not finished OOBE or is in Audit Mode. Complete OOBE and re-run. (e) If the log shows VMD hardware detection was indeterminate; deferring because the driver set cannot be safely determined. and the state file was not updated, a PnP enumeration error prevented the VMD hardware presence check from completing. Resolve the PnP service issue (Windows device management, an antivirus/EDR product blocking device enumeration, a device in an error state) and re-run. (f) If the log shows OS-fallback deferred: C: could not be confirmed fully decrypted (Test-VolumeEncrypted=…) and the state file was not updated, the dedicated partition could not be created and the OS-fallback target is not confirmed fully decrypted. Wait for C: to reach FullyDecrypted or complete decryption of C: (manage-bde -off C:), then re-run. (g) If the log shows Dedicated replacement deferred before partition deletion (<Reason>). and the state file was not updated, the v45 pre-shrink deferral fired (v46 patch 2 added two reasons; v47 added registered source changed before disable). The old recovery partition is still present. If the reason is registered source changed before disable, simply re-run — the v47 race detector caught a Windows Update servicing event during candidate preparation; the source is now stable and the next run will re-select and prepare a fresh candidate. For any other reason, resolve the constraint (free space on C:, correct the disk layout, address the oversized partition, retry the transient read failure, resolve the active-route resolution failure, or investigate the shrink or route-restore failure), then delete C:\Recovery\OEM\winre_partition_deferred.json and, if you also want to clear the deployment identity, C:\Recovery\OEM\winre_state.json to force a retry. If the reason is active WinRE location could not be resolved, note that as of v48 patch 1 the guard fires ahead of the pre-shrink and ahead of reagentc /disable, so the machine is left with WinRE still Enabled — see troubleshooting.md for the re-registration procedure. (h) If the log shows Registered WinRE source changed during candidate preparation - aborting before /disable. The old WinRE route remains intact; no partition changes have been made at this site. and the state file was not updated, the v47 race detector fired at the Step 5 /disable site. WinRE is still Enabled, no partition touched, no WIM deployed. The checkpoint was reset to 2 and base.wim and any stale winre_optimized.wim were removed. Simply re-run — this is the design’s intended response to a source that changed mid-preparation, not a failure. (i) If the log shows Enable-only /enable failed (attempt N of 3) or Enable-only /enable refused with the BitLocker error after the target partition was confirmed unencrypted (attempt N of 3) and the state file was updated with a non-"ok" LastEnableResult, the deployment is current and only the enable step failed. Investigate the enable failure itself; the next run retries enable-only. After three consecutive failures the loop-breaker fires (exit code 3). (j) If the log shows Another WinRE Manager instance is already running (program lock file is exclusively held), a concurrent instance was running. This is not a failure — the other instance is doing the work. Do not investigate; wait for the other instance to complete, then re-check. If your orchestration re-queues soft failures, be aware that the re-queue may also exit 2 until the first instance releases the lock. (k) If the log shows Offline fallback: the machine requires a full update (state file is stale or unhealthy), but the driver manifest is unavailable, the network was unavailable and the state file indicates a full update is needed. No operator action is required — the next scheduled run with network will complete the work. If the log instead shows Offline fallback: using state file's stored DesiredStateId …, the fast path fired successfully and this is a degraded-success, not a deferral. (l) If the log shows Unsupported OS architecture '<arch>' and the state file was not updated, the v48 architecture gate refused. This is a stable deferral: any machine whose architecture is not x64 will continue to exit 2 on every run until the manager adds support or the machine is replaced. (m) If the log shows intervening anchor is N MiB smaller than the plan requires to seat the recovery partition at the disk tail and the state file was not updated, the v48 surplus rejection fired. The old recovery partition is intact; no partition was touched. Extend the anchor, or reduce the desired recovery partition size, then delete the state file and deferral marker to force a retry. (n) If the log shows recovery-typed partitions exist beyond the intervening anchor's recovery cluster; this layout is not supported and the state file was not updated, the v48 multi-intervening rejection fired. Same stable deferral as v47. (o) If the log shows Offline fallback: stored LocalInputsId <hash> does not match the current locally-computable inputs <hash> and the state file was not updated, the v48 offline hardware-drift guard fired. The machine is unchanged; the next run with network recomputes the DSI and either converges or defers normally. (p) If the log shows Base WIM copy hash mismatch: source=..., copied=... - rejecting candidate or Base WIM copy is unreadable after Copy-Item - rejecting candidate, the v47 patch 2 base-WIM copy-integrity check rejected the candidate. The candidate base.wim was removed, the checkpoint was reset to Step 2, and the run exited EXIT_WARNING. Investigate whether the source changed during acquisition. Cases (b), (c), (d), (e), (f), (g), (h), (j), (k), (l), (m), (n), (o), and (p) leave the machine unchanged. Cases (a) and (i) update the state file. |
| 3 | Do not retry automatically. Investigate the log immediately. If the log shows FATAL: WinRE is not enabled at exit on a machine that no longer has a recovery partition, follow the troubleshooting.md recovery procedure before retrying. If the log shows Refusing to retry reagentc /enable, resolve the enable failure, delete the state file, then re-run. If the log shows Driver manifest unavailable and no state file exists, the machine has no state file and no network; retry when the network is available. If the log shows Cannot rename because item at '<workspace>\winre.wim' does not exist and an earlier line shows Could not set up program lock at …, investigate why the lock could not be acquired (permissions on C:\ProgramData\OEM\Logs\, a missing directory, a transient filesystem issue); the run proceeded unprotected and collided with another instance. |
Do not use exit code 0 as the sole health signal. A machine that reached OS-fallback exits with 2, which is a legitimate “the machine is functional but the design goal was not achieved” signal. If your deployment policy requires dedicated recovery partitions, treat 2 as a soft failure and route it to a queue.
Do not configure retry loops that ignore the exit code and re-run unconditionally. None of the deferral states is made better by retrying — the same gate will fire on the next run. Wait until the underlying condition resolves (manage-bde -status C: reads a safe state on the OS-fallback route, the PnP enumeration error clears, the machine has finished OOBE, the pre-shrink constraint is freed, or the marker is cleared), then re-run. Two v47-specific retry exceptions:
For the enable-failure counter, do not retry blindly: the counter is designed to break a silent loop, and after three consecutive failures the loop-breaker fires and requires manual intervention. Investigate the enable failure itself rather than cycling the script. For the concurrent-instance deferral, the correct action is to wait; the other instance is already doing the work.
/disable race detector, the WIM_READY checkpoint’s source binding, and the metadata-based drift detector that together shape the new v47 exit cases.DeployedWinREMetadata field (v47), the offline fallback’s residual risk, and the LocalInputsId field (v48 patch 1, shipped).