HomeNewsletterCommunityMVP FeedToolsArchiveBlogToday's NewsAboutServicesQuick Links Subscribe free
← Back to Blog
Windows Update Windows UpdateSetupDiagFeature UpdateWindows SetupTroubleshootingRegistryEvent LogWindows 11

SetupDiag already named your upgrade failure: reading the report Windows Setup left on the device

IA
Imran Awan
23 August 2026

A feature update fails. You get a rollback, a user with a wasted morning, and a five-digit hex code that means nothing on its own. So you do the normal thing: you re-queue the update, you tell the user to undock, and you run Disk Cleanup to free some space "in case that was it".

Meanwhile, on that exact device, Windows has already written down the root cause. In plain English. With a rule name.

Microsoft ships a diagnostic tool called SetupDiag. It reads the Windows Setup logs, matches what it finds against a published set of named failure rules, and reports which one hit. That much is reasonably well known. What almost nobody acts on is the part that makes it genuinely free: Windows Setup runs SetupDiag for you, automatically, when an upgrade fails. The verdict is already on the disk and already in the registry before you open a ticket.

I went looking on my own machine - a Windows 11 25H2 corporate laptop, build 26200.9168 - expecting to find nothing. I found a complete failure record from 14 May 2025. Fifteen months old. Never read, never cleared, sitting in the registry with the matched rule name, the error pair, the target build and the elapsed time. Nobody on this device has ever looked at it.

That is the whole point of this post. Before you touch a driver, a service or a folder, read what the analyser already told you.

The short version

Windows Setup carries SetupDiag.exe inside %SystemDrive%\$Windows.~bt\Sources and runs it automatically when an upgrade fails, with four fixed parameters. The output lands in two places: %WinDir%\Logs\SetupDiag\SetupDiagResults.xml and the registry key HKLM\SYSTEM\Setup\SetupDiag\Results. Read the registry key first - on my device it holds 14 values including the matched rule name and the error pair, and it is richer than the XML file beside it. Microsoft publishes 64 named rules with GUIDs, so the rule name maps to a documented cause. The catch: when the Windows.old folder goes, SetupDiag.exe goes with it - so the standard "run Disk Cleanup" reflex destroys the logs, the setup minidump and the tool that reads them, in one click.

The problem: the verdict is already on the device

SetupDiag is a diagnostic tool whose whole job is to answer the question you are about to spend two hours on. Microsoft's description is unambiguous: it "works by examining Windows Setup log files" and "attempts to parse these log files to determine the root cause of a failure to update or upgrade the computer to Windows".

It does this by rule matching. It walks a set of rules held in an XML file, one at a time, and reports which rule the log evidence matches. Each rule has a name, a GUID and a documented description. Microsoft's published rules table currently lists 64 named rules, from BitLockerHardblock through DuplicateUserProfileFailure to the generic FindRollbackFailure.

That matters more than it first appears. A raw error code tells you a number. A matched rule name tells you a class of cause that Microsoft has already written a paragraph about. UnknownDriverMigrationFailure and DuplicateUserProfileFailure both surface as generic rollbacks in your dashboard; the remediation for one is removing a driver package, the remediation for the other is deleting an unused local account. The rule name is the difference.

Microsoft's own upgrade resolution-procedures page pushes you at it directly: "You should also try running the free SetupDiag tool provided by Microsoft, which can automatically find the reason for an upgrade failure."

And on modern Windows it has already run

Here is the bit that turns SetupDiag from "a tool I should download" into "a report I should read". Microsoft documents that SetupDiag is included with Windows Setup in all currently supported versions of Windows, and that during the upgrade process Setup extracts all its source files - SetupDiag.exe included - to %SystemDrive%\$Windows.~bt\Sources. Then: "If there's an issue with the upgrade, SetupDiag automatically runs to determine the cause of the failure."

So the first diagnostic command on a failed-upgrade device is not a command at all. It is a read.

PowerShell - reading the automatic SetupDiag record (REAL output, this device)
# Read-only. No tool to download, no service to stop, no reboot. 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 RollbackElapsedTime = 00:00:00 # 14 values. A named rule. A code pair. A target build. An elapsed time. # Written 2025-05-14. I read it on 2026-08-23. Fifteen months untouched.

Read that record for a moment and notice how much diagnosis it hands over for free. The rule is FindAbruptDownlevelFailure, so the failure happened in the downlevel phase - inside the old OS, before any reboot. UpgradeElapsedTime is 27 seconds. Every rollback timestamp is 01/01/0001 00:00:00, the .NET zero date, which means no rollback ever ran.

Twenty-seven seconds, downlevel only, no rollback. Whatever went wrong here, nothing was committed and nothing was reverted. This was never a driver problem. It could not have been - Setup never got as far as touching drivers. Anyone who "fixed" this by updating a graphics driver and retrying would have been right by accident.

Context: SetupDiag data only exists if Windows Setup ran. That is not the same as "an update ran". A 24H2 to 25H2 move on an already-patched device is an enablement package - on this machine, KB5054156 installed on 4 February 2026 - which is a servicing package handled by the component store, not a Setup-driven upgrade. No Setup, no Panther logs, no SetupDiag record, no WER setup event. A Windows 10 to Windows 11 move, or 23H2 to 24H2, is a full Setup pass and does produce all of it. Establish which mechanism you are dealing with before you go hunting for artefacts that were never created.

Nothing ever clears the record

There is no expiry on this key. Setup writes it on failure and it stays until something explicitly overwrites it - which means the next Setup failure, not the next successful update. That cuts both ways.

The good news is that the evidence survives. On my device the registry record outlived the very logs it was generated from, and it survived a 24H2-to-25H2 release change, a servicing stack update, and eighteen months of monthly cumulative updates.

The bad news is that a stale record will happily send you chasing a ghost. If you read ProfileName and act on it without reading DateTime, you will diagnose someone else's problem from last year. On this device that gap is fifteen months wide. DateTime is not a nice-to-have field; it is the field that decides whether the rest of the record is evidence or noise.

Decision flow: whether you touched the device before reading the SetupDiag evidence, and the five-step verification path

Why it happens: Setup runs the analyser, then buries it

The mechanism is simple and entirely documented. When Setup detects a failure it invokes the copy of SetupDiag.exe it already extracted, with four fixed parameters:

/ZipLogs:False   /Format:xml   /Output:%windir%\logs\SetupDiag\SetupDiagResults.xml   /RegPath:HKEY_LOCAL_MACHINE\SYSTEM\Setup\SetupDiag\Results

Every one of those four choices has a consequence you should know about.

/ZipLogs:False means Setup does not bundle the logs it just analysed. The analysis is preserved; the raw evidence is not. If you later want to re-run a newer SetupDiag against the same logs, you have to have kept them yourself.

/Format:xml means the on-disk artefact is XML, not the friendly text log you get from a manual run. Do not go looking for SetupDiagResults.log after an automatic run - it will not be there.

/Output: and /RegPath: pin the two destinations. And that /RegPath value is the single most useful piece of trivia in this whole article, because it is not where a manual run writes.

The two registry paths, and why one of them evaporates

Microsoft flags this explicitly: "When Windows Setup runs SetupDiag automatically, the registry path isn't the same as the default registry path when SetupDiag is run manually." Automatic runs go to HKLM\SYSTEM\Setup\SetupDiag\Results. Manual runs, with no /RegPath specified, go to HKLM\SYSTEM\Setup\MoSetup\Volatile\SetupDiag.

Look hard at the word Volatile in that second path. That is not decoration. A volatile registry key exists only in memory and is discarded at shutdown. So if you run SetupDiag manually, do not pass /RegPath, and then reboot the machine before reading the result, the registry copy is gone. You still have the output file, but the registry copy you might have planned to collect remotely no longer exists.

On my device that key is absent, which is exactly right: nobody has ever run SetupDiag manually here, and even if they had, the machine has rebooted many times since.

PowerShell - the XML file, and the volatile key that is not there (REAL)
PS C:\> Get-ChildItem "$env:WinDir\Logs\SetupDiag" Name Length LastWriteTime ---- ------ ------------- setupdiagresults.xml 1081 5/14/2025 11:24:41 AM PS C:\> Get-Content "$env:WinDir\Logs\SetupDiag\setupdiagresults.xml" <?xml version="1.0" encoding="utf-16"?> <SetupDiag xmlns="https://docs.microsoft.com/.../upgrade/setupdiag"> <Version>1.7.0.0</Version> <ProfileName>FindAbruptDownlevelFailure</ProfileName> <ProfileGuid>55882B1A-DA3E-408A-9076-23B22A0472BD</ProfileGuid> <LogErrorLine>2025-05-14 11:24:17, Error MOUPG CSetupResponseTemplate<class IDlpResponse>::OnCancel(240): Result = 0x800704C7</LogErrorLine> <FailureData>Error: SetupDiag reports abrupt down-level failure. Last Operation: Error: 0x800704C7 - 0x40004</FailureData> <FailureDetails>ErrorCode = 0x800704C7, ExCode = 0x40004</FailureDetails> </SetupDiag> # Note what is MISSING: no <SystemInfo> block at all. Microsoft's sample XML # has one, with manufacturer, model, BIOS, firmware type, upgrade times. # This auto-run record has none of it - 1,081 bytes total. PS C:\> Test-Path 'HKLM:\SYSTEM\Setup\MoSetup\Volatile\SetupDiag' False # The manual-run default path. Volatile = memory only, discarded at shutdown.

That comparison is worth stating plainly, because it inverts the advice you would expect. On this device the registry record is richer than the file. The XML holds six elements and no system information. The registry holds fourteen values, including HostOSVersion, TargetOSVersion with its build lab string, and all six timing fields.

So if you were planning to collect SetupDiagResults.xml across the fleet and skip the registry, you would be collecting the smaller half of the evidence. Collect the registry key.

Gotcha: do not use ProfileGuid as the primary key in your reporting. Microsoft's published rules table contains a genuine collision - DeviceInstallHang and DriverPackageMissingFileFailure are both listed with GUID 37BB1C3A-4D79-40E8-A556-FDA126D40BC6. Those are two different failures with two different remediations (a hang during device installation versus a driver package with a missing file), and a GUID-keyed lookup cannot tell them apart. Group and pivot on ProfileName. Keep the GUID as a secondary reference only.

The tool deletes itself, and takes the evidence with it

Now the trap. Microsoft states it in one sentence and most people skim past it: "If the upgrade process proceeds normally, the Sources directory including SetupDiag.exe is moved under %SystemDrive%\Windows.Old for cleanup. If the Windows.old directory is deleted later, SetupDiag.exe is also removed."

So the tool is not a permanent part of Windows. It rides along inside the setup payload and it is disposed of with that payload. SetupDiag.exe has never been in System32 and is not there now - I checked on this device and it is absent, exactly as the documentation implies.

Add the two facts Microsoft publishes about Windows.old and the picture gets worse. Disk Cleanup, under "clean up system files", offers to remove the previous Windows installation. And even if nobody clicks it: "Ten days after you upgrade to Windows, your previous version of Windows is automatically deleted from your PC." The warning attached to it is blunt - "If you delete your previous version of Windows, this can't be undone."

You therefore have a ten-day evidence window by default, and a one-click way to close it early.

PowerShell - hunting for the tool that already ran (REAL, this device)
PS C:\> Test-Path "$env:WinDir\System32\SetupDiag.exe" False # Correct and expected. It is not an in-box System32 binary. PS C:\> Test-Path "$env:SystemDrive\Windows.old" False # Gone. So the copy of SetupDiag.exe that produced the May 2025 record is gone too. PS C:\> Get-ChildItem "C:\`$WINDOWS.~BT" -Recurse -Force | >> Select-Object FullName, Length, LastWriteTime FullName Length LastWriteTime -------- ------ ------------- C:\$WINDOWS.~BT\Sources 5/14/2025 11:24:44 C:\$WINDOWS.~BT\Sources\Diagnostics 5/14/2025 11:24:07 C:\$WINDOWS.~BT\Sources\Panther 5/14/2025 11:24:32 C:\$WINDOWS.~BT\Sources\Diagnostics\diagnostics.dat 336 5/14/2025 11:24:18 C:\$WINDOWS.~BT\Sources\Panther\diagerr.xml 8978 5/14/2025 11:24:42 C:\$WINDOWS.~BT\Sources\Panther\diagwrn.xml 11646 5/14/2025 11:24:42 C:\$WINDOWS.~BT\Sources\Panther\setupact.log 88314 5/14/2025 11:24:42 C:\$WINDOWS.~BT\Sources\Panther\setuperr.log 2666 5/14/2025 11:24:32 C:\$WINDOWS.~BT\Sources\Panther\windlp.state-old.xml 460 5/14/2025 11:24:32 C:\$WINDOWS.~BT\Sources\Panther\windlp.state.xml 460 5/14/2025 11:24:32 # Ten items. Every timestamp is 14 May 2025 - the failure itself. # The LOGS survived. The TOOL did not. That is the asymmetry to plan for.

This is the cleanest possible illustration of the trap. The logs SetupDiag parsed are still sitting in $WINDOWS.~BT\Sources\Panther fifteen months later, perfectly readable. The binary that read them is nowhere on the machine. If I wanted to re-analyse those logs with a newer rule set today, I would have to download the tool again first.

Never do this first: on a device that has just failed an upgrade, do not run Disk Cleanup, do not delete $WINDOWS.~BT or Windows.old, and do not let the user re-attempt the update before you have harvested the evidence. That one action destroys three things simultaneously - the setup logs, the setup minidump (setupmem.dmp, which Microsoft documents lands in $Windows.~bt\Sources\Rollback or %WinDir%\Panther\NewOS\Rollback), and SetupDiag.exe itself. There is exactly one documented exception: for 0xC1900107 / MOSETUP_E_CLEANUP_PENDING, Microsoft's own mitigation is to reboot and then use Disk Cleanup on temporary and system files. That is a specific, named code with a specific instruction. It is not a general licence.

How to verify: a five-step read that costs nothing

Here is the order to work in. Every step before step 5 is read-only and takes seconds. Do not skip ahead - the whole value of this sequence is that it stops you from destroying evidence in step 5 that you needed in step 1.

1
Read HKLM\SYSTEM\Setup\SetupDiag\Results. Check DateTime before you read anything else. If it does not correspond to the failure you are investigating, you are looking at a historical record - note it and move on rather than acting on it. If it does match, read ProfileName and look that rule up in Microsoft's published table. You may be finished here.
2
Read %WinDir%\Logs\SetupDiag\SetupDiagResults.xml. Same content, sometimes with a <SystemInfo> block the registry lacks, sometimes with less than the registry has. Cross-check the two. A mismatch means two different Setup failures wrote at different times.
3
Check the WER event. Application log, event 1001, event name WinSetupDiag02. This gives you the result code and extend code as parameters P5 and P6, independently of SetupDiag. If SetupDiag matched no rule, this event may still carry the code pair.
4
If all three are empty, prove whether Setup ever ran. An enablement package or a plain cumulative update never invokes Windows Setup, so there is nothing to find. Look for a Setup-log package event for the KB instead. Absence of SetupDiag data is not a fault - it is often the answer.
5
Only now harvest the logs and run SetupDiag yourself. Copy the Panther folders off the device first, then run the current tool against them offline. This is the first step that touches anything, and it is deliberately last.

The registry reference

Every value below lives under one key. On an automatically-generated record this key held exactly 14 values on my device.

HKLM\SYSTEM\Setup\SetupDiag\Results
ValueMeaningWhat to look for
ProfileNameThe name of the rule SetupDiag matched.The single most useful field on the device. Look it up in Microsoft's rules table for the documented cause and remediation. Mine reads FindAbruptDownlevelFailure.
ProfileGuidThe rule's unique identifier.Use as a cross-reference only, never as a database key - at least two published rules share one GUID.
SetupDiagVersionVersion of the analyser that wrote the record.1.7.0.0 here. The rule set ships in an XML file that is updated with new tool versions, so an older version can report "no match" where a current one would match. Note it before you conclude the failure is unknown.
DateTimeWhen SetupDiag ran.Read this first, always. Nothing clears this key, so the record can be arbitrarily old. Mine is dated 05/14/2025.
FailureDataThe rule's plain-English verdict, plus the actual log line it matched on.Contains a verbatim setuperr.log entry with its timestamp. That timestamp is your entry point into the raw logs - search for it directly rather than reading from the top.
FailureDetailsThe error pair in a fixed, parseable format.ErrorCode = 0x800704C7, ExCode = 0x40004. Decode ErrorCode first; it is usually a plain Win32 or HRESULT value.
HostOSVersionThe OS build the upgrade started from.Confirms the direction of travel. 10.0.26100 here, so the device was on 24H2 at the time.
TargetOSVersionThe OS build being installed, with its build lab string.10.0.26100.3624 (ge_release_svc_prod3.250321-2034) identifies the exact target payload - useful for spotting a fleet-wide bad target rather than a per-device fault.
UpgradeStartTimeWhen Setup began.Correlate against the user's account of events and against the Panther log timestamps.
UpgradeEndTimeWhen Setup stopped.Compare with DateTime - SetupDiag runs after Setup gives up, so its stamp should be slightly later.
UpgradeElapsedTimeTotal duration.The cheapest sanity check available. 00:00:27 cannot be a driver migration failure; Setup never got that far.
RollbackStartTimeWhen rollback began.01/01/0001 00:00:00 is the zero date and means no rollback occurred - nothing was committed to be reverted.
RollbackEndTimeWhen rollback finished.Same zero-date logic. A populated pair here means the device really did go up and come back down.
RollbackElapsedTimeHow long the rollback took.00:00:00 alongside zeroed stamps confirms the failure was pre-commit. A long rollback duration points you at the rollback logs instead.

The event log reference

One channel, one event ID. This is the Application log, source Windows Error Reporting.

Event IDMessage / event nameWhat it tells you
1001Informational WER report, event name WinSetupDiag02Microsoft's documented home for the Setup result code and extend code. Ten parameters; P5 is the result code and P6 the extend code. Also carries links to the relevant log files.
1001Informational WER report, event name WinSetupDiag01The legacy equivalent. Microsoft notes: "For legacy operating systems, the Event Name was WinSetupDiag01." Search for both names if you support a mixed estate.

The ten parameters are worth memorising, because two of them are the whole reason to open the event and the rest tell you the shape of the attempt.

ParameterMeaningDocumented values / 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

P2 and P4 together are a fast triage pair. P2=5 means the event came from the rollback path, so the device got far enough to need reverting. P4=2 means cancel rather than failure - a very different conversation with the user.

Step 3 and step 4, on a real device

My device is a good demonstration of the negative result, and of why the negative result is informative rather than frustrating.

PowerShell - the WER event that is not there, and why (REAL)
# Microsoft's documented query, verbatim from the Windows Error Reporting page. PS C:\> $e = Get-WinEvent -FilterHashtable @{LogName="Application"; >> ID="1001"; Data="WinSetupDiag02"} Get-WinEvent : No events were found that match the specified selection criteria. # Is the channel healthy? Sample the same ID without the name filter: PS C:\> (Get-WinEvent -FilterHashtable @{LogName='Application';ID=1001} ` >> -MaxEvents 400).Count 400 # 400 other event 1001 entries. The log is fine. WinSetupDiag02 count: 0. # So did Windows Setup ever run on this device? Check the delivery mechanism: PS C:\> Get-HotFix | Where-Object HotFixID -eq 'KB5054156' | >> Select-Object HotFixID, Description, InstalledOn HotFixID Description InstalledOn -------- ----------- ----------- KB5054156 Update 2/4/2026 12:00:00 AM # KB5054156 is the Windows 11 25H2 ENABLEMENT PACKAGE. A servicing package, # not a Setup pass. 24H2 -> 25H2 here never invoked Windows Setup at all, # which is precisely why there is no WinSetupDiag02 event to find. # Microsoft's own caveat on that page: these event logs are only available # if Windows was updated from a previous version to a new version.

Two conclusions from one absent event. First, the absence is explained, not mysterious - and an explained absence is a finished diagnostic step. Second, the record that does exist in the registry is from a completely different event in May 2025, which is why step 1's instruction to read DateTime first is not pedantry.

Tip: for a wave of feature-update failures across a fleet, the cheapest possible triage is a remote read of four values - ProfileName, FailureDetails, DateTime and SetupDiagVersion - from HKLM\SYSTEM\Setup\SetupDiag\Results. Filter to records whose DateTime falls inside your deployment window, then group by ProfileName. Twenty devices reporting one rule name is a fleet problem with one documented remediation. Twenty devices reporting eleven different rule names is not a single incident, and treating it as one will waste the week. This read needs no agent, no tool deployment and no reboot.

The fix: running SetupDiag yourself, online and offline

Everything so far has been reading. Now the tool itself - for when the automatic record is missing, stale, matched no rule, or was written by an older version than the one currently shipping.

Requirements, and one that trips people up

Three documented requirements. The destination version of Windows must be a currently supported version. .NET Framework 4.7.2 or newer must be installed. And SetupDiag.exe must be run from an elevated command prompt "for it to work properly" - Microsoft repeats that warning three separate times on the page, which tells you how often it is the actual problem.

The .NET requirement is the one worth checking before you blame the tool. Microsoft publishes the exact query, and on my device it passes comfortably:

reg.exe query "HKLM\SOFTWARE\Microsoft\Net Framework Setup\NDP\v4" /s
  → Version : 4.8.09221   Release : 533509   satisfies the 4.7.2 minimum

Microsoft's guidance on which build to run is unusually direct: "When SetupDiag is run manually, Microsoft recommends running the latest version of SetupDiag." Because the rules live in an XML file that ships with the binary, an old copy of the tool is an old copy of the rule set. Do not keep a 2019 SetupDiag.exe in your toolkit share and expect it to recognise a 2026 failure mode.

The parameters

ParameterWhat it doesDefault / notes
/?Displays help information.Running SetupDiag.exe with no parameters at all also just displays help.
/Output:Full path and file name for the results log.Defaults to SetupDiagResults.log in the directory the tool runs from. UNC paths work if the executing context can reach them. Quote the whole path if it contains a space.
/LogsPath:Full path to the logs to parse.Specifying this switches the tool into offline mode automatically. Accepts a flat folder or a tree - it searches all child directories recursively. Defaults to checking the current system.
/ZipLogs:True or False - zip the results plus every log parsed.Defaults to true on a manual run. The automatic run explicitly sets it to False, which is why Setup leaves you no log bundle.
/Format:xml or json output.Text format is used if this is not specified. Use json if you are feeding results into a reporting pipeline.
/Scenario:Recovery or Debug.Recovery processes reset and recovery logs and ignores setup logs. Debug debugs memory dumps, if the debug binaries are installed.
/VerboseWrites an extra diagnostic log with debugging detail.By default SetupDiag only logs major errors about itself. Use this when you are reporting a problem with the tool, not with the upgrade.
/NoTelSuppresses diagnostic telemetry to Microsoft.The one to remember for regulated or air-gapped environments.
/RegPathWrites failure information to a registry path you choose.Must start with HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER and be writable at the current elevation. Without it, results go to the volatile HKLM\SYSTEM\Setup\MoSetup\Volatile\SetupDiag.
/AddRegAdds failure information to the registry in offline mode.By default SetupDiag only writes to the registry in online mode. Needed if you are analysing another machine's logs and want the result recorded locally.

One deprecation to know: /Mode is gone. It used to pair with /LogsPath to select offline analysis. Now specifying /LogsPath is sufficient and /Mode is unnecessary. If you inherited a script that passes it, that script predates the current tool.

Which folders to copy for an offline run

This is the part to get right on the failing device, because it is the part you cannot redo later. Microsoft names four candidate folders, and says which one matters depends on when the upgrade failed:

Copy the parent folder and all subfolders and let the tool recurse. Do not hand-pick individual files - the rule set correlates across logs, and DebugSetupMemoryDump, DebugSetupCrash and DebugMemoryDump are offline-only rules that need the dump present to fire at all.

Elevated cmd - the four runs worth knowing (documented syntax)
:: 1. Online, on the failing device. It finds its own logs. Nothing to gather. C:\Tools> SetupDiag.exe /Output:C:\SetupDiag\Results.log :: 2. Offline, against logs copied off another machine. :: /LogsPath alone switches to offline mode - /Mode is deprecated. C:\Tools> SetupDiag.exe /Output:C:\SetupDiag\Results.log /LogsPath:D:\Temp\Logs\LogSet1 :: 3. Offline, machine-readable, and record the verdict in the local registry. C:\Tools> SetupDiag.exe /Output:C:\SetupDiag\Results.xml /Format:xml /LogsPath:D:\Cases\4471 /AddReg /NoTel :: 4. A bug check during setup. Dumps CANNOT be debugged in online mode - :: /LogsPath is mandatory, and the Windows Debugging Tools must be installed. C:\Tools> SetupDiag.exe /Output:C:\SetupDiag\Dumpdebug.log /LogsPath:D:\Dump :: Shape of a real match, from Microsoft's published sample output: :: SetupDiag: processing rule: CompatScanOnly. ...No match. :: SetupDiag: processing rule: DISMImageSessionFailure. :: Error: SetupDiag reports DISM provider failure. :: Last Phase: Safe OS :: Last Operation: Apply Optional Component status :: SetupDiag found 1 matching issue.

Two things about that sample output are worth internalising. It walks every rule and prints "No match" for each miss, so a long run is normal - Microsoft notes under known issues that "some rules can take a long time to process if the log files involved are large". And it counts matches. When there is more than one, Microsoft's rule is explicit: "When SetupDiag indicates that there were multiple failures, the last failure in the log file is typically the fatal error, not the first one."

Gotcha: a "no match" result is not the same as "the logs are clean". SetupDiag matches against a finite rule set held in an XML file, and Microsoft says that file "might be updated with new and updated rules as new versions of SetupDiag are made available". A failure mode newer than your copy of the tool produces no match. Before you conclude the failure is undiagnosable, check SetupDiagVersion in the record, download the current build, and re-run it against the logs you kept. This is the single best argument for keeping the logs even after you have the verdict.
Get-SetupDiagEvidence.ps1 HTML report: automatic registry verdict, XML output, raw log folder discovery, and a live SetupDiag re-run, all in one self-contained page

Every registry value, log-folder check and the live SetupDiag re-run in this post, collected by one script and rendered as one report — not four separate manual steps.

Tip: the script behind this report, Get-SetupDiagEvidence.ps1, is on GitHub at github.com/Imran76Awan/Windows-Patching-Scripts. Registry and log-folder checks are read-only; the live SetupDiag run is opt-in behind -AllowDownload and only ever writes the output file you point it at. Pass -Redact to mask the hostname, and -OutputHtml to get the report shown above.

What the file names on disk actually mean

The artefacts SetupDiag reads and writes are not interchangeable, and picking the wrong one wastes real time. Everything in this table is present on my device or documented by Microsoft.

FileWhere it livesRole, and what it is worth
SetupDiag.exe%SystemDrive%\$Windows.~bt\Sources during setup; moved under Windows.old afterwards. Never in System32 - verified absent on this device.The analyser. Requires .NET 4.7.2+ and elevation. Deleted along with Windows.old, so treat it as disposable and keep your own copy from the Microsoft Download Center.
setupact.log$Windows.~bt\Sources\Panther (downlevel), ...\UnattendGC (OOBE), ...\Rollback (rollback), Windows\Panther (post-upgrade)Microsoft calls it "the most important log for diagnosing setup issues". Size is no guide to health - the copy in Windows\Panther on my device is 546.9 MB from a successful install.
setuperr.logSame locations as setupact.logError lines only. The fast read - 2,666 bytes on this device's failed attempt versus 88,314 for the matching setupact.log. This is the file SetupDiag quotes in LogErrorLine.
SetupDiagResults.xml%WinDir%\Logs\SetupDiagThe automatic run's output. Small - 1,081 bytes here - and on this device it carries less than the registry key does.
setupmem.dmp%SystemDrive%\$Windows.~bt\Sources\Rollback or %WinDir%\Panther\NewOS\RollbackThe minidump Setup extracts if the OS bug-checks mid-upgrade. Only usable with /LogsPath plus the Windows Debugging Tools. First casualty of a cleanup.
BlueBox.logWindows\Logs\MosetupCommunication between setup.exe and Windows Update. Documented for WSUS and Windows Update downlevel failures and for 0xC1900107. Present on my device at 46,935 bytes, timestamped 11:24:44 - three seconds after the failure record was written.
diagerr.xml / diagwrn.xmlAlongside the Panther logsSetup's own error and warning digests. Present in this device's failure folder at 8,978 and 11,646 bytes. Useful cross-checks when setuperr.log is a single repeated stack.

Proof it worked: decoding a real 15-month-old record

Everything above is procedure. This section is the payoff: an unbroken chain of custody from a real log line on a real device, through SetupDiag's analysis, to a defensible verdict - all of it recovered read-only, fifteen months after the fact, on a machine nobody had ever investigated.

Start with the raw evidence. The setuperr.log that SetupDiag parsed is still on disk. It is 2,666 bytes and 21 lines, and it is a single unwinding call stack:

The actual setuperr.log SetupDiag read - C:\$WINDOWS.~BT\Sources\Panther (REAL)
2025-05-14 11:24:17, Error MOUPG CSetupResponseTemplate<class IDlpResponse> ::OnCancel(240): Result = 0x800704C7 2025-05-14 11:24:17, Error MOUPG CSetupResponseTemplate<class IDlpResponse> ::ExecuteRoutine(142): Result = 0x800704C7 2025-05-14 11:24:17, Error MOUPG CDlpResponseImpl<...>::Execute(1973): 0x800704C7 2025-05-14 11:24:17, Error MOUPG CDlpActionImpl<...>::ExecuteResponse(1398): 0x800704C7 2025-05-14 11:24:17, Error MOUPG CDlpActionDU::ExecuteDUSetup(2391): Result = 0x800704C7 2025-05-14 11:24:17, Error MOUPG CDlpActionDU::ExecuteRoutine(455): Result = 0x800704C7 2025-05-14 11:24:17, Error MOUPG CDlpTask::ExecuteAction(3334): Result = 0x800704C7 2025-05-14 11:24:17, Error MOUPG CDlpTask::Execute(1643): Result = 0x800704C7 2025-05-14 11:24:17, Error MOUPG CSetupManager::ExecuteInstallMode(1048): 0x800704C7 2025-05-14 11:24:17, Error MOUPG CSetupManager::ExecuteDownlevelMode(610): 0x800704C7 2025-05-14 11:24:17, Error MOUPG CDlpActionImpl<...>::GetResults(742): 0x8007139F 2025-05-14 11:24:17, Error MOUPG CSetupManager::GetDUSetupResults(8466): 0x8007139F 2025-05-14 11:24:32, Error MOUPG CDlpTask::Cancel(991): 0xC1800104[gle=0x00000003] 2025-05-14 11:24:32, Error MOUPG CDlpTask::Cancel(995): 0xC180010A[gle=0x00000003] 2025-05-14 11:24:32, Error MOUPG CSetupManager::Execute(346): Result = 0x800704C7 2025-05-14 11:24:32, Error MOUPG CSetupHost::Execute(517): Result = 0x800704C7 # Every line tagged MOUPG - one of Microsoft's documented logging components. # Line 1 is the deepest frame. Everything below it is the stack unwinding.

Now the chain. Six links, each one verifiable against the previous:

1
11:24:05 - setupact.log opens with *************** SetupHost Logging Begin ***************. That matches UpgradeStartTime in the registry exactly.
2
11:24:17 - twelve seconds in, OnCancel fires with 0x800704C7 inside CDlpActionDU::ExecuteDUSetup. This is the deepest frame and the first error in the file.
3
11:24:32 - CSetupHost::Execute returns the same code and Setup stops. That matches UpgradeEndTime. Total run: 27 seconds, matching UpgradeElapsedTime.
4
11:24:41 - SetupDiag runs, matches FindAbruptDownlevelFailure, and writes both the XML and the registry key. DateTime confirms the stamp.
5
11:24:42 - setupact.log closes with **************** SetupHost Logging End ****************. SetupDiag finished before Setup tore down its own UI - the analysis is genuinely part of the failure path, not a later sweep.
6
11:24:44 - BlueBox.log in Windows\Logs\Mosetup gets its last write. An independent artefact, from the same event, corroborating the whole timeline.

Four separate artefacts - the registry key, the XML, two Panther logs and a Mosetup log - agree to the second. That is what a solid diagnosis looks like, and it took a read-only registry query to find the thread to pull.

Decoding the codes, and refusing to decode one

0x800704C7 is an HRESULT wrapping a Win32 error: the low word 0x4C7 is 1223 decimal, which Microsoft documents as ERROR_CANCELLED - "The operation was canceled by the user."

0x8007139F wraps 0x139F, 5023 decimal: ERROR_INVALID_STATE - "The group or resource is not in the correct state to perform the requested operation." Which is exactly what you would expect a results-fetch call to return after the operation it was asking about had already been cancelled. It is a consequence, not a cause.

And 0xC1800104 and 0xC180010A? I am not going to tell you what those mean, because Microsoft does not. The published modern-setup error table runs from 0xC1900100 upward; the only 0xC180xxxx code documented anywhere on that page is 0xC1800118, an unrelated WSUS decryption-key problem. These two are not in the list.

That restraint matters. It is very tempting to pattern-match 0xC180010A against 0xC190010a (MOSETUP_E_UNKNOWN_CMD_LINE) because they look similar. Different facility, different meaning, and a confident guess here would send a colleague down a completely fabricated path. The two codes appear on CDlpTask::Cancel lines fifteen seconds after the real error, in the cancellation cleanup. Note them, do not build on them.

The extend code that does not fit - and what to trust instead

One honest loose end. FailureDetails gives ExCode = 0x40004. Microsoft's documented convention for extend codes is that the first digit is the setup phase, which would put this in phase 4. But the matched rule is FindAbruptDownlevelFailure, and the log line that triggered it is CSetupManager::ExecuteDownlevelMode. Downlevel is phase 1.

Those two readings cannot both be right, and I am not going to invent a reconciliation. What I will do is say which one I trust. The rule name and the log line are direct evidence from the artefact; the phase-digit convention is a documented convention for 0xC1900101 pairs, and this is not one - the result code here is 0x800704C7. When a decoding convention disagrees with a matched rule and a verbatim log line, believe the rule and the line. This is the same discipline as refusing to guess at the 0xC180xxxx codes: the value of a diagnostic is destroyed the moment you start filling gaps with plausible inventions.

The verdict

Put it together. On 14 May 2025 this device started a Windows Setup pass from build 26100 toward 10.0.26100.3624. Twelve seconds in, during the Dynamic Update action of the downlevel phase, the operation was cancelled. Setup unwound and exited at 27 seconds. No rollback ran, because there was nothing to roll back - Setup never reached a reboot, never touched a driver, never migrated a profile.

Nothing on this machine was broken. Nothing needed fixing. The correct action was to retry the update, and indeed the device went on to reach 25H2 without incident.

Now compare that against the reflex. Faced with a failed feature update and a hex code, the standard sequence is: reset SoftwareDistribution, run SFC, run DISM /RestoreHealth, run Disk Cleanup, retry. That sequence would have "worked", in the sense that the retry succeeded. It would also have consumed an hour, touched four subsystems that were never implicated, destroyed the Panther logs and the SetupDiag record, and taught the engineer precisely nothing - leaving them equally blind the next time.

The registry read took under a second and produced a defensible answer. That is the entire argument of this series in one worked example: the diagnosis is cheaper than the cargo-cult fix, and it is the only one of the two that leaves you smarter.

PowerShell - and a closing warning about reading Error counts as verdicts (REAL)
# The Panther logs from this device's ORIGINAL, SUCCESSFUL install: PS C:\> Get-ChildItem "$env:WinDir\Panther" -File | >> Sort-Object LastWriteTime -Desc | Select-Object -First 4 Name,Length Name Length LastWriteTime ---- ------ ------------- setupact.log 573433781 3/15/2025 6:04:20 PM # 546.9 MB setup.etl 1552384 3/15/2025 5:58:24 PM diagwrn.xml 2901430 3/15/2025 5:58:24 PM setuperr.log 9099 3/15/2025 5:58:12 PM PS C:\> Get-Content "$env:WinDir\Panther\setuperr.log" -Tail 3 2025-03-15 17:43:48, Error MIG Failure while calling IPostApply->ApplySuccess for Plugin={..IasMigPlugin.dll..}. Error: 0x80010105 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] # 9,099 bytes of Error-level lines, MIG and SP components, real HRESULTs. # This install SUCCEEDED. The device has been running that OS for 17 months. # Error lines in setuperr.log are NOT a verdict. SetupDiag's matched rule is.

That last block is the reason to prefer the rule name over your own log reading. A 9 KB pile of Error lines on a successful install is normal. Grepping for the word "Error" and counting hits produces a number that correlates with nothing. SetupDiag does not count errors - it matches a pattern against a named rule, and reports the rule. That is a qualitatively better answer, it is free, and on a modern device it has usually already been produced.

Check it first.

References

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

More from EndpointWeekly

Windows Update
0xC1900101 is not one error: the extend code after it names the…
0xC1900101 is a generic rollback code with nine documented causes. The extend code beside…
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…