HomeNewsletterCommunityMVP FeedToolsArchiveBlogToday's NewsAboutServicesQuick Links Subscribe free
← Back to Blog
Windows Update Windows UpdateFeature Update0xC1900101Windows SetupSetupDiagDriversTroubleshootingWindows 11

0xC1900101 is not one error: the extend code after it names the phase that killed your feature update

IA
Imran Awan
23 August 2026

A feature update fails on eleven machines overnight. Every one of them reports the same thing: 0xC1900101. So you do what everybody does. You tell the user to unplug their dock, you get approval to disable the endpoint agent, and you queue the update again. Four of them work. Seven fail again.

You have learned nothing, because you never read the second half of the error.

0xC1900101 is not the error. Microsoft's own words are blunt about it: "A result code of 0xC1900101 is generic and indicates that a rollback occurred." Generic. It tells you Windows Setup gave up and put the old OS back. It does not tell you where, when, or why. That information lives in a completely separate number that Setup returns alongside it, and most reporting surfaces throw it away.

The short version

Windows Setup returns two codes on failure: a result code and an extend code, written as 0xC1900101 - 0x30018. The result code is the generic rollback signal. The extend code is the actionable one: its first digit is the setup phase and its last two digits are the operation, and Microsoft publishes the decoding tables for both. Decode the pair and you go from "a driver, somewhere" to "the sysprep operation in the first boot phase", which tells you exactly which log to open and which class of driver to suspect. Only then do you go hunting in setuperr.log and setupapi.dev.log for the specific file. Clean-booting first is the one move that guarantees you never find out which driver it was.

The problem: one code, nine documented root causes

Microsoft documents nine distinct 0xC1900101 pairs, each with its own cause and its own mitigation. They are not variations on a theme. One is a recovery-environment build failure. One is a WIM apply failure. One is a display driver hanging during data migration. One is a filter driver from a virtualisation agent blocking disk writes. The remediation for those four has almost nothing in common - yet if your reporting captured only the result code, all four look identical on your dashboard.

Why the extend code goes missing

Setup returns both codes, but not every consumer of that data keeps both. Microsoft calls this out directly on the error codes page: "If only a result code is returned, this can be because a tool is being used that was not able to capture the extend code."

So the first diagnostic act is not troubleshooting at all. It is recovery of a number you were supposed to have been given. The documented place to find it is the Application event log, where Windows Error Reporting writes an informational event 1001 named WinSetupDiag02.

PowerShell - Microsoft's documented query for the code pair
# The exact query Microsoft publishes on the Windows Error Reporting page. # P5 holds the result code. P6 holds the extend code. PS C:\> $events = Get-WinEvent -FilterHashtable @{LogName="Application";ID="1001";Data="WinSetupDiag02"} Get-WinEvent : No events were found that match the specified selection criteria. # REAL RESULT on my Windows 11 25H2 device (build 26200.9168). Nothing. # The same log holds 200+ other event 1001 entries, so the channel is fine. # Microsoft's own caveat on that page explains it: these events exist only # "if Windows was updated from a previous version of Windows to a new version". # This device went 24H2 -> 25H2 by ENABLEMENT PACKAGE, not by Windows Setup. # No mosetup run means no phases, no extend code, and no 0xC1900101 is possible.

That absence is itself a diagnostic result, and a useful one. Microsoft documents that "Devices updating from Windows 11, version 24H2 use an enablement package" - a small switch that activates dormant features rather than swapping the OS. An enablement package is a servicing operation. It has no downlevel phase, no WinPE pass and no second boot, so it cannot produce a setup phase code.

Context: before you spend an afternoon decoding extend codes, establish that the device actually ran Windows Setup. A 24H2 to 25H2 move on an already-patched machine is an enablement package. A Windows 10 to Windows 11 move, or a 23H2 to 24H2 move, is a full Setup run with all four phases. Only the second kind can return 0xC1900101 at all - and knowing which path a fleet took tells you immediately whether driver compatibility is even in scope.

The reflex that destroys the evidence

The standard advice for 0xC1900101 is to uninstall antivirus, disconnect every peripheral, and clean boot. Microsoft does publish those steps and they often work. But look at what a clean boot does: it changes the loaded driver set wholesale. If the update then succeeds, you know only that something in the difference was responsible - not what. Next month the same driver ships to the same fleet and you start over, because you never wrote down a filename.

Never do this first: do not delete the $WINDOWS.~BT folder, do not run Disk Cleanup, and do not let the user re-attempt the update before you have harvested the rollback logs. Microsoft documents that the minidump, the rollback event logs and the device install log all live under $Windows.~bt\Sources\Rollback - and that if the upgrade later proceeds normally, the whole Sources directory is moved under Windows.old and is removed when Windows.old is deleted. Every retry and every cleanup overwrites or destroys the only copy of the evidence.

Why it happens: the extend code is a phase plus an operation

Windows Setup does not perform an upgrade in one pass. It runs four phases, with a reboot between each, and Microsoft states that "Progress is tracked in the registry during the upgrade process" using a volatile key that exists only while the upgrade is running.

Each phase runs in a different environment, with a different set of drivers loaded. That is the whole reason the phase digit is diagnostic: it tells you which driver environment was live when the wheels came off.

What 0xC1900101 actually is

The result code has a name. In Microsoft's modern setup error table, 0xC1900101 is listed as MOSETUP_E_SETUP_PLATFORM, described as "The Setup Platform has encountered an unspecified error." That is a component reporting its own failure to continue, not a description of a fault.

Gotcha: Microsoft publishes a general rule for decoding result codes - identify Win32 versus NTSTATUS from the first digit, then look up the last four digits in the relevant table. Do not apply that rule to 0xC19xxxxx codes. Those are mosetup-defined values with their own published symbolic names, so 0xC1900101 resolves to MOSETUP_E_SETUP_PLATFORM in the modern setup errors table, not to whatever 0x0101 happens to mean in the NTSTATUS list. Reading it the generic way produces a confident, wrong answer.

Splitting the extend code

Microsoft's decoding rule has exactly three steps: use the first digit for the phase, use the last two digits for the operation, and match both against the published tables.

0xC1900101 - 0x30018
0xC1900101 = result code. Generic rollback. MOSETUP_E_SETUP_PLATFORM. 3 = first digit = phase 3 = SP_EXECUTION_FIRST_BOOT. 18 = last two digits = operation 0x18 = SP_EXECUTION_OP_SYSPREP. Reads as: the sysprep operation failed during the first boot phase.

That is the entire trick. And it is checkable: Microsoft's rollback guidance says separately that "The device install log is helpful if rollback occurs during the sysprep operation (extend code 0x30018)". The arithmetic and the prose agree.

The phase table

These are the six documented phase values. The fourth column is Microsoft's own list of example extend codes seen in each phase, which is a useful sanity check on your decode.

HexPhase constantWhat runs in itDocumented example codes
0SP_EXECUTION_UNKNOWNPhase not recorded. Treat the decode as untrustworthy.-
1SP_EXECUTION_DOWNLEVELRuns inside the old OS. Files copied, components gathered.-
2SP_EXECUTION_SAFE_OSWindows PE. Recovery partition configured, files expanded, updates installed, rollback prepared.0x2000C, 0x20017
3SP_EXECUTION_FIRST_BOOTBooted into the new OS. Initial settings applied.0x30018, 0x3000D
4SP_EXECUTION_OOBE_BOOTFinal settings applied. Microsoft also calls this the second boot phase.0x4000D, 0x40017
5SP_EXECUTION_UNINSTALLThe rollback path itself.0x50000, 0x50015

Note the naming collision, because it will confuse you when you cross-reference Microsoft's own pages. Phase 4 is SP_EXECUTION_OOBE_BOOT in the constants table, but the resolution procedures article calls it "the second boot phase". The troubleshooting article reconciles them explicitly: "Second boot phase: Final settings are applied. This is also called the OOBE boot phase." Same phase, two names.

There is also a hard rule buried in the docs that saves time. Microsoft states 0xC1900101 "can be thrown at any stage of the upgrade process, with the exception of the downlevel phase." So a reported pair of 0xC1900101 - 0x1xxxx is self-contradictory. If you see one, distrust the capture rather than the machine.

The operation table

The last two digits identify what Setup was doing. This is the full published list.

HexOperation constantWhat it was doing
0SP_EXECUTION_OP_UNKNOWNOperation not recorded
1SP_EXECUTION_OP_COPY_PAYLOADCopying the installation payload
2SP_EXECUTION_OP_DOWNLOAD_UPDATESDownloading dynamic updates
3SP_EXECUTION_OP_INSTALL_UPDATESInstalling dynamic updates
4SP_EXECUTION_OP_INSTALL_RECOVERY_ENVIRONMENTBuilding WinRE
5SP_EXECUTION_OP_INSTALL_RECOVERY_IMAGEInstalling the recovery image
6SP_EXECUTION_OP_REPLICATE_OCReplicating optional components
7SP_EXECUTION_OP_INSTALL_DRIVERSInstalling drivers
8SP_EXECUTION_OP_PREPARE_SAFE_OSPreparing the WinPE environment
9SP_EXECUTION_OP_PREPARE_ROLLBACKStaging the rollback
ASP_EXECUTION_OP_PREPARE_FIRST_BOOTPreparing first boot
BSP_EXECUTION_OP_PREPARE_OOBE_BOOTPreparing OOBE boot
CSP_EXECUTION_OP_APPLY_IMAGEApplying the WIM
DSP_EXECUTION_OP_MIGRATE_DATAMigrating data
ESP_EXECUTION_OP_SET_PRODUCT_KEYSetting the product key
FSP_EXECUTION_OP_ADD_UNATTENDApplying unattend
10SP_EXECUTION_OP_ADD_DRIVERAdding a driver
11SP_EXECUTION_OP_ENABLE_FEATUREEnabling a feature
12SP_EXECUTION_OP_DISABLE_FEATUREDisabling a feature
13SP_EXECUTION_OP_REGISTER_ASYNC_PROCESSRegistering an async process
14SP_EXECUTION_OP_REGISTER_SYNC_PROCESSRegistering a sync process
15SP_EXECUTION_OP_CREATE_FILECreating a file
16SP_EXECUTION_OP_CREATE_REGISTRYCreating registry data
17SP_EXECUTION_OP_BOOTBooting
18SP_EXECUTION_OP_SYSPREPRunning sysprep
19SP_EXECUTION_OP_OOBERunning OOBE
1ASP_EXECUTION_OP_BEGIN_FIRST_BOOTEntering first boot
1BSP_EXECUTION_OP_END_FIRST_BOOTLeaving first boot
1CSP_EXECUTION_OP_BEGIN_OOBE_BOOTEntering OOBE boot
1DSP_EXECUTION_OP_END_OOBE_BOOTLeaving OOBE boot
1ESP_EXECUTION_OP_PRE_OOBEPre-OOBE work
1FSP_EXECUTION_OP_POST_OOBEPost-OOBE work
20SP_EXECUTION_OP_ADD_PROVISIONING_PACKAGEApplying a provisioning package
Gotcha: Microsoft attaches an explicit shelf-life warning to these tables - "Extend codes reflect the current Windows 10 upgrade process, and might change in future releases" - and notes the published values correspond to Windows 10 version 1607. They have proved stable and they still decode current failures correctly, but treat a decode that produces a nonsensical phase and operation pairing as a signal to stop trusting the arithmetic and corroborate against SetupDiag and the logs instead.

How to verify: recover the pair, then name the driver

Here is the order. Each step either produces the answer or narrows the next step. Nothing here changes the machine.

Step 1 to 3: recover the code pair

1. Read the SetupDiag result from the registry. Windows Setup runs SetupDiag automatically when an upgrade fails, and Microsoft documents the exact parameters it uses, including /RegPath:HKEY_LOCAL_MACHINE\SYSTEM\Setup\SetupDiag\Results. That key is the fastest read on the box and it is remotely queryable, which makes it the right first move across a fleet.

HKLM\SYSTEM\Setup\SetupDiag\Results
ValueMeaningWhat to look for
FailureDetailsThe result and extend code pair, named as ErrorCode and ExCode.This is the whole prize. Read ExCode and decode it.
ProfileNameWhich SetupDiag rule matched.Corroborates your phase decode. A rule naming a phase that disagrees with your arithmetic means stop and re-check.
ProfileGuidThe rule's unique identifier.Use it to look the rule up in Microsoft's published rules table.
DateTimeWhen SetupDiag ran.Check this before anything else. The key is not cleared, so a stale entry will happily mislead you.
FailureDataSetupDiag's narrative plus the matching log line.Contains the raw setuperr.log line and its component tag, which points at the right log.
HostOSVersion / TargetOSVersionBuild you came from and build you were going to.Confirms which upgrade attempt this record describes.
UpgradeElapsedTimeHow long the attempt ran.Sanity check on the failure class. A driver rollback takes many minutes; seconds means something aborted early.
RollbackStartTime / RollbackEndTimeWhen the rollback ran.All zeroes means no rollback happened - so it was not a 0xC1900101 class failure at all.
SetupDiagVersionVersion of the tool that produced the record.Older versions carry fewer rules. Microsoft recommends running the latest build manually.

Here is that key read on my own device. It is a real record, and it is a worked example of why you check DateTime first.

PowerShell - real SetupDiag record, Windows 11 25H2 corporate device
PS C:\> Get-ItemProperty 'HKLM:\SYSTEM\Setup\SetupDiag\Results' ProfileName : FindAbruptDownlevelFailure ProfileGuid : 55882B1A-DA3E-408A-9076-23B22A0472BD SetupDiagVersion : 1.7.0.0 DateTime : 05/14/2025 11:24:41 FailureData : Error: SetupDiag reports abrupt down-level failure. Last Operation: Error: 0x800704C7 - 0x40004 LogEntry: 2025-05-14 11:24:17, Error MOUPG CSetupResponseTemplate<class IDlpResponse>::OnCancel(240): Result = 0x800704C7 FailureDetails : ErrorCode = 0x800704C7, ExCode = 0x40004 HostOSVersion : 10.0.26100 TargetOSVersion : 10.0.26100.3624 (ge_release_svc_prod3.250321-2034) UpgradeStartTime : 14/05/2025 11:24:05 UpgradeEndTime : 14/05/2025 11:24:32 UpgradeElapsedTime : 00:00:27 RollbackStartTime : 01/01/0001 00:00:00 RollbackEndTime : 01/01/0001 00:00:00 # Read this the disciplined way, in order: # DateTime is MAY 2025. Today is August 2026. This record is 15 months stale. # Result code is 0x800704C7, NOT 0xC1900101. Win32 0x4C7 = ERROR_CANCELLED, # "The operation was canceled by the user." Nobody's driver did this. # UpgradeElapsedTime = 27 seconds. A driver rollback never finishes that fast. # RollbackStartTime is all zeroes - no rollback ran at all. # Component tag on the failing line is MOUPG, not SP. # Verdict: a cancelled upgrade attempt. Zero driver work indicated. # Note the tension worth knowing about: ExCode 0x40004 decodes to phase 4, # yet the matched rule is FindAbruptDownlevelFailure. When arithmetic and rule # disagree, trust the rule, the component tag and the result code - not the maths.

Four independent signals in one key all say the same thing, and none of them is "driver". Had I skipped straight to the extend code and decoded phase 4, I would have gone looking for a filter driver in the second boot phase and found nothing, because there was nothing to find.

2. Cross-check the Application log. The event is the authoritative record of the pair as Setup reported it.

Event log channel: Windows Logs > Application (source: Windows Error Reporting)
Event IDMessage / event nameWhat it tells you
1001WinSetupDiag02 - informational, ten parametersThe authoritative result and extend code pair for a Setup failure. Also carries links to the log files for that attempt.
1001WinSetupDiag01 - legacy event nameSame role on legacy operating systems. Search for both names before concluding no event exists.

The parameter positions matter, because the raw event data is an unlabelled list of ten strings.

ParameterHoldsDocumented example
P1The setup scenario1=Media, 5=WindowsUpdate, 7=Media Creation Tool
P2Setup modex=default, 1=Downlevel, 5=Rollback
P3New OS architecturex=default, 0=X86, 9=AMD64
P4Install resultx=default, 0=Success, 1=Failure, 2=Cancel, 3=Blocked
P5Result error code0xc1900101
P6Extend error code0x20017
P7Source OS build9600
P8Source OS branchNot typically available
P9New OS build16299
P10New OS branchrs3_release

P4 is worth a second look. If it reads 2 (Cancel), you are not chasing a driver, whatever P5 says. That single field would have short-circuited the stale record above.

3. If both are empty, run SetupDiag yourself. Microsoft ships it inside Windows Setup, extracted to %SystemDrive%\$Windows.~bt\Sources during the upgrade, and recommends downloading the current build for manual runs. Note that when you run it by hand without /RegPath, results land at HKLM\SYSTEM\Setup\MoSetup\Volatile\SetupDiag - a different key from the automatic one. Two keys, two provenances; do not read one and think you are seeing the other.

Step 4 to 6: turn the phase into a log, and the log into a filename

4. Let the phase choose the log. This is the payoff of decoding. Microsoft's log table is indexed by phase, and says so plainly: "The log files are located in a different folder depending on the Windows Setup phase. Recall that the phase can be determined from the extend code."

Log filePhase: locationWhen to use it
setupact.logDown-Level: $Windows.~BT\Sources\PantherAll downlevel failures, and the starting point for rollback investigations.
setupact.logRollback: $Windows.~BT\Sources\RollbackInvestigating generic rollbacks - that is, 0xC1900101.
setupact.logOOBE: $Windows.~BT\Sources\Panther\UnattendGCRollbacks in the OOBE phase - operations 0x4001C through 0x4001F.
setupact.logPost-upgrade: Windows\PantherPost-upgrade issues, and the logs left behind by a run that completed.
setuperr.logSame as setupact.logEvery error encountered during installation. Always open this one first.
setupmem.dmp$Windows.~BT\Sources\RollbackBug check during upgrade. Setup extracts a minidump.
setupapi.dev.log$Windows.~BT\Sources\RollbackDevice install failures - specifically extend code 0x30018.
BlueBox.logDown-Level: Windows\Logs\MosetupCommunication between setup.exe and Windows Update.

5. Read setuperr.log, not setupact.log. Both files exist in the same folder. One of them is readable.

PowerShell - real Panther log sizes on the same device
PS C:\> Get-ChildItem 'C:\Windows\Panther\setup*.log' | Select-Object Name,Length Name Length ---- ------ setupact.log 573433781 setuperr.log 9099 # Real measurement. setupact.log is 573,433,781 bytes - about 547 MB. # setuperr.log is 9,099 bytes. 63 lines. A 63,000-to-1 reduction. # Notepad will fight you for ten minutes on the first file and lose. PS C:\> Get-Content 'C:\Windows\Panther\setuperr.log' | >> ForEach-Object { if ($_ -match ',\s+\w+\s+(\w+)\s') { $matches[1] } } | >> Group-Object | Sort-Object Count -Descending Count Name ----- ---- 15 SP 9 CONX 1 MIG 1 Apply 1 DU 1 MOUPG # Component tags, and they match Microsoft's documented list exactly. # SP = setup platform, MIG = migration engine, CONX = compatibility. # Microsoft names those three as the useful ones. Start with SP.
Tip: triage by component tag before you read a single message. A failure whose last error line is tagged SP is a setup platform operation failure and your extend code decode is trustworthy. A last line tagged MIG points at data migration - a profile, a file, a registry key - not a driver. CONX is the compatibility appraiser and usually noise. MOUPG means the failure happened above the setup platform, and your phase digit may be meaningless. Microsoft documents the tag position as the third element of every log entry, after the timestamp and the log level.

6. Find the last occurrence, not the first. Microsoft's documented procedure is specific about direction: search for the result code, then "find the last occurrence of the code", searching upward from the bottom of the file. Then look for two exact strings: Shell application requested abort and Abandoning apply due to error for object. SetupDiag's own documentation carries the same warning: "When SetupDiag indicates that there were multiple failures, the last failure in the log file is typically the fatal error, not the first one."

Here is why that discipline is not optional. This is real content from that 9 KB setuperr.log, from a device that upgraded successfully.

setuperr.log - real SP lines from a SUCCESSFUL upgrade
2025-03-15 16:48:49, Error SP pSPExecuteApply: Apply operation failed. Error: 0x0000002C 2025-03-15 16:48:50, Error SP Apply (machine-specific apply, offline phase): Migration phase failed. Result: 44, no specific error 2025-03-15 16:48:50, Error SP Operation failed: Offline portion of machine-specific and machine-independent apply operations. Error: 0x8007042B[gle=0x000000b7] ... 2025-03-15 17:45:54, Error SP CProvisioningMigration::DoExecute: ProvMigration failed. Error: 0x80070003[gle=0x0000012a] 2025-03-15 17:58:12, Error SP SETUPPLATFORMEXE: Error connecting to the progress pipe. Error: 0x00000002[gle=0x00000002] # These are genuine lines from C:\Windows\Panther\setuperr.log. # Windows\Panther is the POST-UPGRADE location, so this run finished. # The machine is fine. It is running now. And yet: # 0x8007042B is the exact code Microsoft uses in its own worked # failure example (8007042B - 0x4000D, second boot MIGRATE_DATA). # THE LESSON: errors in setuperr.log are not proof of your failure. # 63 error lines on a machine that upgraded cleanly. You must anchor on # the LAST occurrence of YOUR result code, or you will confidently # remediate a benign line from a completed upgrade.

Step 7 to 8: name the driver

7. For a device install failure, open setupapi.dev.log. This is where a driver stops being a category and becomes a file. Microsoft's published example ends with the exact marker you are looking for.

setupapi.dev.log - the documented shape of a driver verdict
# Structure and field names below are from Microsoft's published example # on the Log files page. Hardware IDs will differ on your device. >>> [Device Install (UpdateDriverForPlugAndPlayDevices) - PCI\VEN_8086&DEV_8C4F] >>> Section start 2023/09/26 20:13:01.623 dvi: Created Driver Node: dvi: HardwareID - PCI\VEN_8086&DEV_8C4F dvi: InfName - ...\lynxpointsystem.inf dvi: DevDesc - Intel(R) QM87 LPC Controller - 8C4F dvi: Signer Score - WHQL dvi: DrvDate - 04/04/2016 dvi: Version - 10.1.1.18 ! ndv: No better matching drivers found for device 'PCI\VEN_8086&DEV_8C4F...' <<< [Exit status: FAILURE(0xC1900101)] # Four fields are what you actually want out of this file: # HardwareID -> identifies the device across the whole fleet # InfName -> the driver package to pull or update # Version + DrvDate -> is a newer package available from the OEM? # Signer Score -> WHQL versus unsigned changes who you escalate to # On my device the live equivalent, C:\Windows\INF\setupapi.dev.log, # is 3,935,513 bytes. Search it, do not scroll it.

8. If it bug-checked, get the stop code. For a 0x4000D failure, Microsoft's instruction is to look for setupmem.dmp and "Review the rollback log and determine the stop code", and it publishes a sample crash block showing Crash 0x0000007E detected with four bugcheck parameters. SetupDiag can debug that dump for you if the Windows Debugging Tools are installed and you pass /LogsPath, since memory dumps cannot be debugged in online mode.

The binaries and files in this path

Knowing where these actually live saves a detection script that silently never fires.

FileRoleWhere it lives
SetupDiag.exeParses setup logs and matches them against a rules XML to name a root cause.Not in System32. Extracted to %SystemDrive%\$Windows.~bt\Sources during upgrade, then moved under Windows.old. Verified absent from System32 and the Windows root on my 25H2 device.
SetupPlatform.exeOwns the phase and operation queue. It is the SP component in the logs and the thing MOSETUP_E_SETUP_PLATFORM refers to.Not in System32 itself - verified at C:\Windows\System32\oobe\SetupPlatform\SetupPlatform.exe on my 25H2 device. Appears in real log lines as SETUPPLATFORMEXE.
setuphost.exeSurfaces failures early in the upgrade, before the setup platform is running.Ships with the setup media, not the installed OS - a depth-limited search of the Windows tree on my device did not find it. Named in SetupDiag's FindSetupHostReportedFailure rule.
appraiser.sdbCompatibility appraiser database. The source of the CONX Appraiser lines that fill setuperr.log with noise.%WINDIR%\Panther - verified present, 2,811,457 bytes, alongside Appraiser_Data.ini and the CompatData_*.xml scan results.
wimmount.sysWIM file system driver. Setup mounts the install image through it, so a broken registration fails the SafeOS WIM apply.C:\Windows\System32\drivers\wimmount.sys - verified present, 79,344 bytes, FileDescription "Wim file system Driver". Two SetupDiag rules exist purely for it.
setup.etlETW trace of Setup performance events, openable in Event Viewer.%WINDIR%\Panther - verified present, 1,552,384 bytes.
setupapi.dev.logPlug and Play device installation log. Where a driver gets named.%WINDIR%\Inf\ for the live OS - verified 3,935,513 bytes; the rollback copy is under $Windows.~BT\Sources\Rollback\setupapi\.
miglog.xmlRecord of what the migration engine actually moved.%WINDIR%\Panther - verified present at 336,444,054 bytes, about 321 MB.

The fix: what each phase actually tells you to do

Now the extend code earns its keep. Each documented pair carries its own cause and its own first move, and they are not interchangeable.

Extend codeDecodes toMicrosoft's documented causeDocumented first move
0x20004SAFE_OS / INSTALL_RECOVERY_ENVIRONMENT"Windows Setup encountered an error during the SAFE_OS with the INSTALL_RECOVERY_ENVIRONMENT operation. This error is caused by out-of-date drivers."Uninstall antivirus; remove unused SATA devices and unused devices and drivers; update drivers and BIOS.
0x2000cSAFE_OS / APPLY_IMAGEUnspecified error during WIM apply in the WinPE phase. Out-of-date drivers, or disk corruption.Run checkdisk to repair the file system; update drivers; disconnect everything except mouse, keyboard and display.
0x20017SAFE_OS / BOOT"A driver has caused an illegal operation... This is a SafeOS boot failure, typically caused by drivers or non-Microsoft disk encryption software. This can also be caused by a hardware failure."Open setuperr.log and setupact.log in %windir%\Panther and locate the problem drivers, then update or uninstall them.
0x30018FIRST_BOOT / SYSPREP"A device driver has stopped responding to setup.exe during the upgrade process."Disconnect all peripherals except mouse, keyboard and display; get updated drivers from the hardware vendor. Read setupapi.dev.log.
0x3000DFIRST_BOOT / MIGRATE_DATA"Installation failed during the FIRST_BOOT phase while attempting the MIGRATE_DATA operation. This can occur due to a problem with a display driver."Disconnect peripherals; update or uninstall the display driver.
0x4000DOOBE_BOOT / MIGRATE_DATA"A rollback occurred due to a driver configuration issue... This can occur because of incompatible drivers."Look for setupmem.dmp in $Windows.~BT\Sources\Rollback, get the stop code, and act on the driver the bug check names.
0x40017OOBE_BOOT / BOOT"Upgrade failed after the second reboot. This is caused by a faulty driver. For example: antivirus filter drivers or encryption drivers."Clean boot, then upgrade. Microsoft documents a named case here: Citrix VDA's CtxMcsWbc filter driver preventing setup from writing to disk.
0x4001EOOBE_BOOT / PRE_OOBE"Installation failed in the SECOND_BOOT phase with an error during PRE_OOBE operation."Treated as generic; fall back to the 0xC1900101 procedures.

Read down the "decodes to" column and the pattern is the point. Phase 2 failures are WinPE-environment problems - storage stacks, disk encryption filters, firmware. Phase 3 failures are the new OS meeting your hardware for the first time - device and display drivers. Phase 4 failures are filter drivers and security agents now loaded under the new kernel.

That is the inference the extend code buys you. 0x20017 and 0x40017 are the same operation - BOOT - in two different phases, pointing at two entirely different families of software. Disabling your antivirus is reasonable for 0x40017. It is close to irrelevant for 0x20017, where the antivirus filter driver is not even loaded yet.

The one thing to do before any of it

Harvest first. Copy the whole folder, then remediate. Microsoft's guidance for offline SetupDiag analysis is to copy one of \$Windows.~bt\sources\panther, \$Windows.~bt\Sources\Rollback, \Windows\Panther or \Windows\Panther\NewOS, and notes that if you copy the parent folder and all subfolders, SetupDiag searches every subdirectory itself. That is a one-command capture that survives every retry the user makes while you are still reading.

Proof it worked: real setup artefacts from a live device

Everything below was read from one live Windows 11 25H2 corporate device, build 26200.9168, read-only. It shows what the diagnostic surface looks like on a machine that is currently healthy - which is exactly what you need to recognise the abnormal.

PowerShell - setup diagnostic surface inventory, real output
C:\Windows\Panther -> True C:\Windows\Panther\NewOS -> True C:\Windows\Logs\SetupDiag -> True C:\Windows\Logs\Mosetup -> True C:\$WINDOWS.~BT -> False C:\Windows\System32\SetupDiag.exe -> ABSENT C:\Windows\Panther\NewOS\setupact.log -> ABSENT C:\Windows\Logs\SetupDiag\setupdiagresults.xml 1081 bytes 14/05/2025 C:\Windows\Logs\Mosetup\BlueBox.log 46935 bytes 14/05/2025 C:\Windows\Panther\setup.etl 1552384 bytes C:\Windows\Panther\miglog.xml 336444054 bytes C:\Windows\INF\setupapi.dev.log 3935513 bytes C:\Windows\System32\drivers\wimmount.sys 79344 bytes "Wim file system Driver" # Every line here is consistent with the documentation, and each one # is a check you can make on a failing machine: # $WINDOWS.~BT absent = no upgrade in flight, and the rollback logs # for any past attempt are already gone. # SetupDiag.exe absent = expected. It is never in System32. A script # testing System32 will always report missing. # Windows\Panther populated = a Setup run reached post-upgrade. # setupdiagresults.xml dated 14/05/2025 = matches the stale registry # record exactly. Same event, two surfaces.

The setupdiagresults.xml file on disk carried the same failure as the registry key, byte for byte in substance: <FailureDetails>ErrorCode = 0x800704C7, ExCode = 0x40004</FailureDetails>, matched by rule FindAbruptDownlevelFailure. Microsoft documents both destinations for the same run, and having the pair agree is how you confirm you are reading a genuine record rather than a leftover.

Three findings from this device are worth carrying into your own environment.

The stale record is real and it is dangerous. A May 2025 SetupDiag result was still sitting in the registry in August 2026 - fifteen months and one whole feature release later. Nothing cleared it. Fleet reporting that reads HKLM\SYSTEM\Setup\SetupDiag\Results without filtering on DateTime will raise tickets for upgrades that failed over a year ago and have long since been superseded.

A successful upgrade leaves 63 error lines behind. The setuperr.log from the March 2025 run sits in the post-upgrade location, meaning that run completed - and it still holds fifteen SP errors, including 0x8007042B, the very code Microsoft uses in its own documented failure walkthrough. Error lines are not evidence. The last occurrence of your specific result code is evidence.

Log sizes decide your method. setupact.log at 547 MB and miglog.xml at 321 MB are not files you open and read. setuperr.log at 9 KB is. A runbook that says "review setupact.log" without giving a search string is one nobody will follow at 2am.

Tip: the fastest fleet-wide triage for a wave of feature-update failures is a single remote read of FailureDetails, ProfileName and DateTime from HKLM\SYSTEM\Setup\SetupDiag\Results. Group the results by ExCode. If they cluster on one extend code you have one driver problem across the fleet and one phase to investigate. If they scatter across three or four extend codes, you do not have a single root cause and treating it as one will waste the week.

References

Was this post helpful?
React below — no account needed
Share this post
LinkedIn X / Twitter Reddit Bluesky

More from EndpointWeekly

Windows Update
SetupDiag already named your upgrade failure: reading the report…
Windows Setup runs SetupDiag automatically when an upgrade fails, writing the matched…
Windows Update
The folders that look like corruption: Panther, $WINDOWS.~BT and…
A feature update fails and the evidence lands in hidden folders whose names read like…
Windows Update
A feature update failed and setupact.log is 547 MB: read…
Windows Setup keeps its own logs, separate from CBS.log and the WU traces. On this device…