There is one Windows Update failure that outlives every fix in the standard playbook. The device reboots, shows Working on updates, climbs to somewhere between ten and thirty per cent, then announces that it is undoing changes. It boots back to the desktop. Next reboot, the same screen, the same update, the same reversal. Forever.
Clearing SoftwareDistribution does nothing to it. Nor does sfc /scannow. That is not bad luck: the failure is neither in the download nor in the live file set. It sits in a queue of file and registry operations that Windows wrote to disk, scheduled for the next boot, and could not complete.
That queue has a name, a file, its own executable and its own log. Most advice about it can name only the file, and recommends deleting it.
Component-Based Servicing cannot replace a file that running Windows holds open, so it defers those operations into a primitive operations queue serialised to C:\Windows\WinSxS\pending.xml and executed at the next boot by C:\Windows\System32\poqexec.exe — whose own file description reads Primitive Operations Queue Executor. Microsoft documents the consequence that produces the loop: "If subsequent actions are requested, they cannot be processed until the previous pending online action is completed." Read the Setup event log first: a healthy install logs Event 1, Event 2 (Staged), Event 4 (reboot necessary), then Event 2 again (Installed). A device that logs Event 4 every boot and never reaches the second Event 2 is stuck in the queue, not in Windows Update. Microsoft does document renaming pending.xml — but offline, after Dism /Cleanup-Image /RevertPendingActions, paired with clearing PendingXmlIdentifier. The rename alone abandons a half-applied transaction.
The problem: the update that installs at every boot and never finishes
The user-visible symptom is a servicing loop. Every restart re-enters the update screen, fails, reverts, and lands back on the desktop with the same update still listed as pending.
What makes it different from an ordinary download error is when it happens: before the shell is up, in a phase of boot where nothing can tell you anything except a percentage. So the reflex is to attack the only thing visible. Someone finds a forum post and deletes or renames C:\Windows\WinSxS\pending.xml. Sometimes the loop stops. That is not the same as the device being fixed.
pending.xml from a running Windows is not a fix, it is an amputation. The file records a transaction that is already partly applied — some files replaced, some registry keys rewritten, the rest queued. Remove it and Windows loses its own list of what it still owes. Microsoft's component store warning applies to this file as much as any other in it: "Deleting files from the WinSxS folder or deleting the entire WinSxS folder may severely damage your system so that your PC might not boot and make it impossible to update."Four readable facts settle the diagnosis, and none of them changes the device.
- What state does the servicing stack think the package is in — Staged, Install Pending, or Installed?
- Does
pending.xmlexist, and if so, how big and how old? - What did
poqexec.logrecord for the last queue? - Does the
Setuplog show the package advancing, or the same reboot-required event repeating?
Why it happens: a transaction that only a boot can close
The servicing stack, and the one thing it cannot do
Microsoft defines the servicing stack as "the component that installs Windows updates", and states that it "contains the component-based servicing stack (CBS), which is a key underlying component for several elements of Windows deployment" — DISM, System File Checker, changing Windows features or roles, and component repair.
CBS is transactional: an update either applies completely or it is rolled back. But CBS runs inside the operating system it is modifying, and there is one thing it cannot do from there — replace a file that running Windows has open, or rewrite a registry key a loaded hive is holding.
So servicing splits in two. What can be done live is done live: payload expanded, component directories created in WinSxS, manifests registered. That phase ends with the package Staged. What cannot be done live is written down as a list of low-level file and registry operations, and deferred. Those are primitive operations, and the list of them is a primitive operations queue, or POQ.
Where the queue lives, and what runs it
The queue is serialised to XML at C:\Windows\WinSxS\pending.xml and executed at the next boot by poqexec.exe, which runs before Windows is fully up — which is exactly why a progress percentage is all you get.
You do not have to take a blog's word for what POQ stands for. The binary says so itself, in metadata read from the lab device used for this article:
Note the version: 10.0.26100.9156 on a device whose OS build is 26200.9168. It is versioned with the servicing stack, not the OS — because it is part of the servicing stack.
TiWorker.exe and CbsCore.dll are not in System32 at all — they sit in C:\Windows\WinSxS\amd64_microsoft-windows-servicingstack_31bf3856ad364e35_<version>_none_<hash>\, with two versions present: 10.0.26100.1 and 10.0.26100.9156. This is why Microsoft ships servicing stack updates inside the monthly cumulative update, and why a broken servicing stack is so nasty: the code that would repair it is the code that is broken.The binaries worth knowing by name
These are the names that appear when you are reading CBS.log at two in the morning, with paths and versions read from the lab device.
| File | What it does | Where it lives on 24H2 / 25H2 |
|---|---|---|
poqexec.exe | Primitive Operations Queue Executor. Executes the deferred file and registry operations. | C:\Windows\System32\poqexec.exe (10.0.26100.9156) |
TrustedInstaller.exe | Windows Modules Installer. The service that owns servicing transactions and writes CBS.log. | C:\Windows\servicing\TrustedInstaller.exe (10.0.26100.7019) |
CbsApi.dll | Component Based Servicing API DLL. The entry surface callers use to drive CBS. | C:\Windows\servicing\CbsApi.dll (10.0.26100.8737) |
TiWorker.exe | Windows Modules Installer Worker. The process that does the actual servicing work and pins your CPU. | Inside the ...servicingstack... component directory in WinSxS |
CbsCore.dll | The CBS engine itself, shipped side-by-side with the servicing stack. | Inside the ...servicingstack... component directory in WinSxS |
dpx.dll | Delta Package Expander. Expands the differential payload in a cumulative update. | C:\Windows\System32\dpx.dll |
drvstore.dll | Driver Store API. Servicing driver packages goes through here. | C:\Windows\System32\drvstore.dll |
The documented rule that turns a stuck queue into a loop
This is why one stuck update stops every subsequent update rather than just failing alone. Microsoft states it in the DISM Limitations section:
"When you are installing a package in an offline image, the package state is 'install pending' because of pending online actions. In other words, the package will be installed when the image is booted and the online actions are processed. If subsequent actions are requested, they cannot be processed until the previous pending online action is completed."
That is the loop, stated as documentation. A queue that cannot complete never clears, and a queue that never clears blocks the next servicing operation — so the next cumulative update stages, is refused, and tries again at the following boot.
The states you are actually diagnosing
"Pending" is not one state. Microsoft's DISM API enumerates eight.
| State | Value | What it means for a looping device |
|---|---|---|
DismStateStaged | 2 | "The package or feature is staged." Payload is in the component store. Nothing has been committed to the live system yet. |
DismStateInstalled | 4 | "The package or feature is installed." The queue ran and the transaction closed. This is the target. |
DismStateInstallPending | 5 | "The install process for the package or feature is pending. Additional processes are pending and must be completed before the package or feature is successfully installed." This is a device waiting on a POQ. |
DismStateUninstallPending | 1 | The mirror image: an uninstall waiting on a boot. Seen after a failed rollback. |
DismStatePartiallyInstalled | 7 | "Some parts of the package or feature have not been installed." The worst answer. Treat as component store damage, not a queue problem. |
A package sitting at Staged for weeks is a different fault from one at Install Pending. Staged means the commit never started; Install Pending means it started and did not finish.
How to verify: read the queue before you touch it
Everything here is read-only. Work through it in order.
Step 1 — read the Setup event log first
Microsoft's own Windows Update repair article opens with this instruction: "You can check the Setup event log for errors." That channel is Applications and Services Logs > Setup, and the provider writing servicing state changes into it is Microsoft-Windows-Servicing. It is the highest-value log for this failure because it records state transitions, not just errors.
| Event ID | Message (as observed on the lab device) | What it tells you |
|---|---|---|
| 1 | Initiating changes for package <name>. Current state is <X>. Target state is <Y>. Client id: <client>. | A transaction opened. The two states are the whole diagnosis, and Client id names who asked — UpdateAgentLCU for a cumulative update, CbsTask for maintenance, DISM for you. |
| 2 | Package <name> was successfully changed to the <state> state. | A transaction closed successfully. Read the state word: Staged is halfway, Installed is done. 240 of the last 400 entries. |
| 4 | A reboot is necessary before package <name> can be changed to the Installed state. | The primitive operations queue has been written. This is your marker. One occurrence is normal. The same one every boot is the loop. |
| 1013 | Initiating system store corruption detection and repair. Detection Only: 1, Automatically Triggered: 0. | A store scan started — either yours, or scheduled maintenance. Tells you whether someone already ran DISM. |
| 1014 | System store corruption detection and repair has completed. Status: 0x0, Total instances of corruption found: 0, total instances of corruption repaired: 0. | Store scan result. A non-zero corruption count moves you off the queue and onto component store repair. |
Honest caveat: Microsoft publishes no reference catalogue for Microsoft-Windows-Servicing event IDs. The message strings above are the real ones from the lab device, not documented text. The Setup channel itself, and the instruction to check it, are documented.
The query that matters is not "show me errors" but "show me one package's whole life".
Learn that shape: the broken version is the same trace with the last line missing and the fourth repeated.
Step 2 — ask the servicing stack what state it thinks the package is in
Do not trust Settings: the Windows Update UI can say "installed" while CBS still has the package pending. Ask CBS directly.
Microsoft's Stop 7B article uses the offline equivalent as its first diagnostic step — Dism /Image:<OS drive>: /Get-packages — noting you will then "see the Install pending and Uninstall Pending packages". Use that form if the device will not boot at all.
Step 3 — check for the queue file itself, without opening it in place
On the lab device pending.xml is absent, the expected clean-state answer. Presence is not automatically a fault either — a device that staged an update and has not rebooted will legitimately have one. What matters is existence, size and age together.
pending.xml is not a configuration file and there is no documented schema for it. Microsoft never publishes its element names and never suggests hand-editing it. Read it to identify which component the queue is stuck on, and for nothing else. If your plan involves changing a value inside it, the plan is wrong.Step 4 — read poqexec.log, and know its limits
poqexec.exe writes to C:\Windows\WinSxS\poqexec.log. On the lab device that file is 5,321 bytes and holds 21 entries going back to April 2025 — roughly one a month, the cadence of cumulative updates plus reboots. There is no equivalent file in C:\Windows\Panther here; Panther holds Windows Setup's own logs, setupact.log and Setup.etl, which are a different phase of a different process. Here is the tail of the real file, unedited.
The GUID suffix is redacted only because it embeds the device's MAC address. The Transaction UoW value is the useful part: search CBS.log for it to correlate a boot-time queue back to the servicing session that created it.
poqexec.log as proof that a queue ran at boot. On the lab device the final entry is timestamped 43 seconds after the Setup log's Event 4 for KB5120708 and 13.5 hours before the Event 2 confirming Installed. On that evidence the entry is written when the queue is built and validated in the online session, not when it executes at boot. Microsoft documents neither the file nor its format, so treat it as proof a queue was created and use the Setup log to establish whether it ever completed.Step 5 — find the registration in CBS.log
CBS.log is documented at %SYSTEMROOT%\Logs\CBS\CBS.log, with rolled archives beside it as CBS.persist.log and CbsPersist_*.cab. It names the registry value that ties the queue to boot.
Registration happens during ordinary CBS transactions, so its presence in the log means nothing on its own. Assuming otherwise is a classic two-hour dead end.
Step 6 — check the boot-time registry markers
Session Manager runs native-mode programs before the Win32 subsystem starts. The familiar example is BootExecute, which is how autochk runs before Windows. SetupExecute is its servicing sibling.
| Value | Meaning | What to look for |
|---|---|---|
SetupExecute | Native-mode commands run at boot for servicing. This is the value CBS.log reports registering poqexec into. | On the clean lab device: present and empty. A populated value on a device that has already rebooted twice is your loop, in one reading. |
BootExecute | Native-mode commands run at every boot, unrelated to servicing. | Lab device reads autocheck autochk *. Anything beyond that pair deserves a second look, but it is not a servicing signal. |
PendingFileRenameOperations | Files queued for rename or delete at next boot by any installer, not only CBS. | Absent on the clean lab device. Microsoft's Stop 7B recovery procedure explicitly backs up and deletes this value as part of reverting a stuck servicing change. |
Two further keys complete the picture, both named in Microsoft's documentation.
| Value / subkey | Meaning | What to look for |
|---|---|---|
RebootPending (subkey) | CBS's own assertion that it needs a restart to finish something. | Absent on the clean lab device. Present plus a repeating Setup Event 4 is a confirmed stuck queue. |
PendingXmlIdentifier | The pointer CBS uses to bind the component store to a specific pending.xml. Lives in the COMPONENT hive, loaded offline. | Microsoft's recovery procedure loads <OS drive>\Windows\System32\config\COMPONENT as a hive, backs the key up, and deletes this value. Leaving it behind after removing pending.xml is how you get a store that references a queue that no longer exists. |
LastResetBase_UTC | When /ResetBase last ran. Documented as a tip in the DISM reference. | Useful context, not a cause. If /ResetBase ran recently, rollback of earlier updates is already gone. |
Step 7 — land on a root cause
With steps 1 to 6 done you should be on exactly one of these four.
- Nothing is wrong.
Install Pending, one Event 4,pending.xmlnewer than the last boot. Reboot. Most common outcome. - Stuck queue. Event 4 repeating per boot, never advancing past
Install Pending,pending.xmlolder than several boots. Use the recovery below. - Store damage under the queue. Event 1014 with a non-zero corruption count, or a package reading
Partially Installed. Repair the store first; the queue is a symptom. - Never got as far as a queue. Stuck at
Staged, no Event 4, nopending.xml. Nothing is deferred, so nothing boot-time is broken — this is a download, applicability or policy problem, and none of the next section applies.
The fix: the documented order, and why the shortcut is worse
What Microsoft actually documents
The documented recovery is Dism /Cleanup-Image /RevertPendingActions, and the documentation is unusually blunt about its scope:
"If you experience a boot failure, you can use the /RevertPendingActions option to try to recover the system. The operation reverts all pending actions from the previous servicing operations because these actions might be the cause of the boot failure. The /RevertPendingActions option is not supported on a running operating system or a Windows PE or Windows Recovery Environment (Windows RE) image. Important: You should use the /RevertPendingActions option only in a system-recovery scenario on a Windows image that did not boot."
Read that carefully, because it is easy to misread. The option is not supported against a running OS — you cannot point it at /Online. You run it from WinRE, targeting the offline volume with /Image:, as Microsoft's Stop 7B article does. Documented ways in: Shift while selecting Restart, Settings > Recovery > Advanced startup, or recovery media. WinRE also starts itself after "two consecutive failed attempts to start Windows".
The full documented sequence, in order
This is Microsoft's Stop 7B procedure, condensed. The ordering is the point.
- Boot to WinRE and open Command Prompt.
- Run
Dism /Image:<OS drive>: /Get-packagesand record which packages read Install pending or Uninstall Pending. Evidence first. - Run
dism /Image:C:\ /Cleanup-Image /RevertPendingActions, substituting your real partition letter. This step unwinds the transaction rather than abandoning it. - Only now: if
<OS drive>\Windows\WinSxS\pending.xmlstill exists, rename it topending.xml.old. - Load
<OS drive>\Windows\System32\config\COMPONENTas a hive, back up the key, deletePendingXmlIdentifierif present, unload. - Load the
SYSTEMhive, find the activeControlSetviaSelect\Default, and underControl\Session Managerback up and deletePendingFileRenameOperationsif present. Unload.
Why "just delete pending.xml" is dangerous
The advice is not wrong because the file is sacred. It is wrong because of what it leaves behind.
A POQ is one half of a transaction whose other half is already applied: component directories created in WinSxS, manifests registered, and the store's own metadata pointing at a specific queue via PendingXmlIdentifier. Deleting the queue rolls none of that back. It removes the instruction list and leaves the half-finished state. Microsoft's own error taxonomy names the outcomes precisely:
| Code | Symbolic name | What it means once the queue is gone |
|---|---|---|
0x8007371B | ERROR_SXS_TRANSACTION_CLOSURE_INCOMPLETE | "One or more required members of the transaction are not present." This is the literal signature of an abandoned queue. |
0x800705B9 | ERROR_XML_PARSE_ERROR | "Unable to parse the requested XML data." What a truncated or hand-edited pending.xml produces. |
0x80073712 | ERROR_SXS_COMPONENT_STORE_CORRUPT | "The component store is in an inconsistent state." Where a half-applied transaction usually ends up. |
0x800f0831 | CBS_E_STORE_CORRUPTION | "CBS store is corrupted." The same problem, reported by CBS rather than SxS. |
0x800f0984 | PSFX_E_MATCHING_BINARY_MISSING | "Matching component directory exist but binary missing." A component directory created by the online phase whose payload the queue was supposed to deliver. |
That last row is the clearest possible description of the damage: the directory exists, the file does not, and the list that would have put the file there has been deleted.
pending.xml" — Microsoft's own procedure renames it. It is "renaming it is step four of six, offline, after /RevertPendingActions, paired with clearing PendingXmlIdentifier." Every one of those qualifiers is load-bearing, and every one is what gets dropped when the advice is copied.What Microsoft does not document
The boundary matters here, because the gaps are exactly where bad advice grows.
- No Microsoft reference page for
poqexec.exe. It appears in Microsoft Q&A threads and error strings, and its file description names it, but there is no documented command line, no documented switches and no supported way to run it by hand. If a procedure tells you to invoke it manually, it is not from Microsoft. - No documented schema for
pending.xml, and no supported way to edit it. - No documented reference for the
SetupExecutevalue. What is verifiable is that CBS names it in its own log and that it reads empty on a healthy device. - No documented format for
poqexec.log. The field meanings above come from the file's own labels; the timestamp decode is inference from a clean FILETIME conversion, not documentation.
/RevertPendingActions and the documented registry steps do not clear the state, the next move is not a more aggressive registry edit. It is component store repair — DISM /Online /Cleanup-Image /RestoreHealth then sfc /scannow, in that order, per Microsoft's repair article — and then escalation with CBS.log in hand. There is no supported deeper manual surgery on a POQ, and inventing one turns a recoverable servicing fault into a rebuild.Proof it worked: one KB traced across three logs
A fix is proven when the package advances state and the queue stops being recreated. Three read-only readings establish that.
First, the state transition. In the real KB5120708 sequence above, the final line is the entire proof: 2026-08-20 09:14:12 ID=2 Package KB5120708 was successfully changed to the Installed state. The matching poqexec.log entry is timestamped 2026-08-19 19:43:46.
Second, the absence of markers.
Third, the negative test most people forget: prove the queue is not being recreated. Install the next cumulative update, reboot once, re-read the Setup log. You want the five-event sequence ending in Installed state, with exactly one Event 4.
One closing observation from the lab data. Across 21 recorded queues, timings ranged from Registry: 4ms, Files: 20ms to Registry: 7081ms, Files: 20039ms, totals from 1.7 to 52.7 seconds. That spread is why this failure is so badly understood: on most devices, most months, the queue runs in under a minute and nobody learns it exists. You only meet it when it stops.
References
- DISM Operating System Package Servicing Command-Line Options - the
/RevertPendingActionsdescription and its "not supported on a running operating system" scope, plus the Limitations paragraph on blocked subsequent actions. - Stop error 7B or Inaccessible_Boot_Device troubleshooting - the ordered recovery procedure:
Get-packages,/RevertPendingActions, renamingpending.xml,PendingXmlIdentifier,PendingFileRenameOperations. - Fix Windows Update corruptions and installation failures - "You can check the Setup event log for errors", the corruption error-code table used above, and the
CBS.logpaths. - DismPackageFeatureState Enumeration - all eight documented package states with their verbatim descriptions.
- Servicing stack updates - the definition of the servicing stack and CBS, and what depends on it.
- Clean Up the WinSxS Folder - the verbatim warning about deleting files from
WinSxS, wherepending.xmlandpoqexec.logboth live. - Get-WindowsPackage (Dism) - the read-only cmdlet used in step 2.
- Windows Setup Log Files and Event Logs -
%WINDIR%\PantherandSetup.etl, a different artefact from theSetupevent channel. - Windows Recovery Environment (Windows RE) - entry points, and the automatic trigger after two consecutive failed boots.
- Manage the Component Store - what
WinSxSis, and why its contents are not safe to prune by hand.
Measurement note: every output above was captured read-only from one Windows 11 Enterprise device, build 26200.9168, on 23 August 2026. The poqexec.log, CBS.log and Setup extracts are unedited apart from a redacted MAC-derived GUID suffix. Inferences rather than documented facts are labelled as such in the text.