Two codes dominate Windows Update support threads: 0x80070002 and 0x8007000D. Search either and you get the same shotgun blast — reset SoftwareDistribution, run SFC, run DISM, re-register some DLLs, check the clock, blame the antivirus.
That advice is scattershot for a structural reason. Neither code is a Windows Update error code. Both are generic Win32 codes wrapped in an HRESULT, and at least five unrelated subsystems along the update pipeline can raise them.
So the useful question is never "how do I fix 0x80070002". It is "which component raised it". Get that wrong and you will spend an afternoon repairing a subsystem that was working perfectly.
0x80070002 is Win32 error 2, ERROR_FILE_NOT_FOUND — "The system cannot find the file specified." 0x8007000D is Win32 error 13 (0xD), ERROR_INVALID_DATA — "The data is invalid." The 0x8007 prefix encodes only facility 7, Win32: something called a Win32 API and it failed. It names no component. Microsoft's Windows Update error code list by component — the reference organised by subsystem — contains neither code, while the corruption error table on a servicing page contains both. Five distinct sites raise them: the agent datastore, BITS, CBS payload resolution, CBS manifest parsing, and the WSUS metadata fetch. Read WindowsUpdate.log and CBS.log to localise the raise site first. The SoftwareDistribution reset addresses one of the five and destroys the evidence for two.
The problem: codes that Microsoft's own component list does not contain
Start with a negative result, because it is the strongest evidence available.
Microsoft publishes Windows Update error code list by component — the canonical Windows Update Agent reference, broken out by the subsystem that raised each error: Data Store, Download Manager, Update Handler, Protocol Talker, Reporter, Expression Evaluator. Every entry is a WU_E_ or WU_S_ symbol with a component attached.
Neither 0x80070002 nor 0x8007000D appears anywhere on it.
That absence is not an oversight. Those tables list codes the agent defines. Our two are OS-wide Win32 codes that the agent merely relays upward when a lower-level call fails. The agent does not know what went wrong either.
Where both codes do appear together is the "Common corruption errors" table on Microsoft's Fix Windows Update errors page — a servicing-stack document. That pairing is itself a clue about where these codes most often originate, and it is a much better starting point than the WUA component tables.
0x8007000D has a row on Common Windows Update errors: message ERROR_INVALID_DATA, description "Indicates data that isn't valid was downloaded or corruption occurred", mitigation "Try to redownload the update, and then start the installation." 0x80070002 is absent from that page entirely — it has its own dedicated troubleshooting article instead.Decode them and the picture sharpens. Both are plain HRESULT_FROM_WIN32 wrappers, and the arithmetic needs no tooling.
Those message strings are verbatim from Microsoft's System Error Codes (0-499) reference, the documented surface of WinError.h. They are the whole of what the code guarantees.
So 0x80070002 means a file lookup failed — which file, looked up by whom, unknown. And 0x8007000D means some bytes failed a validity check — which bytes, checked by which parser, unknown.
Every popular fix for these codes is a bet on one specific answer to those questions. The fixes are not wrong. They are answers to a question nobody established was being asked.
Why it happens: facility 7 names the failure, never the culprit
An HRESULT is a packed 32-bit value. Microsoft's [MS-ERREF] specification lays out the fields as severity, reserved bits, facility, and code, and describes the eleven-bit facility as "an indicator of the source of the error."
Facility 7 is FACILITY_WIN32, and the spec describes that region precisely: "This region is reserved to map undecorated error codes into HRESULTs." Undecorated is the operative word. Facility 7 is the bucket for errors that arrived with no provenance.
The mapping is a documented one-liner. Microsoft's HRESULT_FROM_WIN32 page masks the input with 0x0000FFFF, ORs in FACILITY_WIN32 << 16, and ORs in 0x80000000 for severity. It preserves what failed and discards who failed. That is the entire problem.
FACILITY_NTWIN32, not FACILITY_WIN32. That is a servicing-internal label from a different mapping path, and it derails people trying to reconcile it with the HRESULT spec. It is not a contradiction, and it is not your evidence for facility 7 — use the [MS-ERREF] table for that.The five places the failing call is actually made
An update scans, downloads, stages, then installs. Different code owns each leg. Each leg opens files and parses data, so each can emit exactly these two codes for reasons with nothing in common.
The agent keeps state under %WINDIR%\SoftwareDistribution — a datastore of known updates plus a Download folder for payloads in flight. Microsoft documents the database itself at %WINDIR%\SoftwareDistribution\Datastore\Datastore.edb. If the agent cannot open its own bookkeeping you get file-not-found; if the file is truncated you get invalid-data. This is bookkeeping failure, not update failure — and it is the only branch the famous SoftwareDistribution reset genuinely targets.
Here is the branch almost everyone mis-reads. Microsoft documents 0x80070002 against BITS with a very specific cause, and it is not a missing payload: it is "The Parameters key is missing" — the service registration itself, HKLM\SYSTEM\CurrentControlSet\Services\BITS\Parameters\ServiceDll, which should point at qmgr.dll. BITS will not start, so nothing downloads. Genuine transfer faults, by contrast, get BITS's own facility — BG_E_ codes in the 0x8020xxxx range. That distinction is the single most useful thing on this page.
Component-Based Servicing installs a package by walking its manifests and locating each file they name. If the file is absent from the package or the component store, CBS logs a miss and returns file-not-found. Microsoft quotes the line shape verbatim: Info CBS Failed to find file: ...DWrite.dll [HRESULT = 0x80070002 - ERROR_FILE_NOT_FOUND]. The download succeeded here. The package is simply incomplete.
Distinct from site 3, and this is the distinction most guides miss entirely. Site 3 is "the manifest named a file and the file is gone." Site 4 is "the manifest itself will not parse." Microsoft documents the CBS.log markers for each: CSI Payload Corrupt and CBS MUM Missing ("A required MUM file is missing from the package") on one side, CSI Manifest Corrupt on the other. The file exists. It is not readable as what it claims to be.
Before anything downloads, the agent fetches cabinet metadata — Microsoft's own words: "Windows Update downloads manifest files and provides them to the arbiter." Point WUServer at a decommissioned or unreachable host and the fetch fails as file-not-found. Nothing on the device is corrupt; the path to the catalog is. Microsoft even gives you the reachability test: confirm you can download http://<WSUSSERVER:port>/iuident.cab without errors.
0x8007000D to an intercepting proxy. It is a popular explanation and Microsoft documents different codes for it: a proxy that mishandles HTTP range requests produces BG_E_INSUFFICIENT_RANGE_SUPPORT (0x80200013) when it "returns the full file instead of the requested range", BG_E_MISSING_FILE_SIZE (0x80200011) when it omits Content-Length, or 0x80d05001 DO_E_HTTP_BLOCKSIZE_MISMATCH on the Delivery Optimization path. Windows Update requires proxies to support range requests per RFC 7233. If your code is 0x8007000D, the proxy is probably not your problem — and chasing it will cost you a day.Five sites, two codes — and the reflex fix addresses one of them.
The binaries that raise these codes
Knowing which file owns which leg turns a log line into a location. Paths and versions below were read from a live Windows 11 25H2 device, build 26200.9168 — that build's values, not universal constants.
| Binary | Role | Where it lives (verified, 26200.9168) |
|---|---|---|
wuaueng.dll | File description Windows Update Agent. The agent engine, and the registered ServiceDll for wuauserv. Microsoft's WUA version-detection doc names this file explicitly as the one that defines the installed WUA version. Owns site 1. | C:\Windows\System32\wuaueng.dll (1509.2607.1012.0) |
wuapi.dll | File description Windows Update Client API. The COM surface callers drive WUA through — so the layer that hands an HRESULT back to a script or to Settings. | C:\Windows\System32\wuapi.dll (1509.2607.1012.0) |
qmgr.dll | File description Background Intelligent Transfer Service. The BITS engine. Microsoft documents this exact path as the correct value of the BITS ServiceDll — the missing-Parameters fault in site 2 is a missing pointer to this file. | C:\Windows\System32\qmgr.dll (7.8.26100.8115) |
dosvc.dll | File description Delivery Optimization. Carries most modern update payloads. Its documented fallback is the HTTP source (CDN), not BITS. | C:\Windows\System32\dosvc.dll (10.0.26100.7309) |
usosvc.dll | File description Update Session Orchestrator Service. The ServiceDll for UsoSvc, which Microsoft defines as the component that "orchestrates the sequence of downloading and installing various update types." | C:\Windows\System32\usosvc.dll (10.0.26100.8737) |
TrustedInstaller.exe | File description Windows Modules Installer. Microsoft confirms the Windows Modules Installer service writes to CBS.log. Sites 3 and 4 are its output. Path below read from the service ImagePath on the lab device, not from documentation. | C:\Windows\servicing\TrustedInstaller.exe |
cbscore.dll | The CBS engine, shipped side-by-side with the servicing stack — which is why servicing stack updates ship inside the monthly cumulative. | Not in System32 — inside the versioned ...servicingstack... component directory under C:\Windows\WinSxS |
One correction worth publishing, because it recurs in DLL lists: usocore.dll is widely cited as the Update Session Orchestrator binary. A recursive search of C:\Windows on this 26200.9168 device returned no such file, and it appears in no Microsoft documentation page. The orchestrator's registered service DLL is usosvc.dll. Verify a path before you build a script around it.
How to verify: localise the raise site before you touch anything
One question: which of the five raised it. Everything below is read-only.
Step 1 — record which of the two codes you have
It matters more than it looks. 0x80070002 is a lookup failure and biases toward sites 1, 3 and 5. 0x8007000D is a validation failure and biases toward sites 1 and 4. Both codes on one device usually means two faults, not one.
Step 2 — produce a readable WindowsUpdate.log
Since Windows 8.1 the client has used Event Tracing for Windows. Microsoft states it plainly: "Windows Update no longer directly produces a WindowsUpdate.log file. Instead, it produces .etl files that aren't immediately readable as written." The traces sit in C:\Windows\Logs\WindowsUpdate and you merge them yourself.
The component tag is the entire diagnostic. Everyone reads the error code and stops, but the code was never the informative part of the line.
-LogPath to a collection folder instead of accepting the Desktop default — on a remote or kiosk device the default lands in whichever profile you elevated as, often not one you can retrieve files from. And take the snapshot before you change anything. Because it is static by design, it becomes your baseline for free, and you can diff it afterwards.Step 3 — if the tag pointed at servicing, go to CBS.log
Microsoft describes CBS.log as the log that "provides insight on the update installation part in the servicing stack", and confirms the Windows Modules Installer service writes to it. It is the authority for sites 3 and 4, and it separates them cleanly.
If neither pattern appears anywhere near the failure timestamp, the servicing stack was never involved and sites 3 and 4 are eliminated. A genuinely useful negative result, and it costs two minutes.
Step 4 — the differential table
This is the table to keep. Left column is "I saw the code in this context"; right column is which subsystem is actually failing.
| Code seen in this context | Actual failing subsystem | What it really means |
|---|---|---|
Either code beside a DataStore or DTASTOR tag in WindowsUpdate.log | Site 1 — WUA datastore (wuaueng.dll) | The agent cannot open or reconcile its own bookkeeping. File-not-found means the datastore is gone; invalid-data means it is truncated, typically after an ungraceful shutdown or a disk-full event. |
0x80070002 and BITS will not start at all | Site 2 — BITS service registration | Not a download problem. The Parameters key is missing, so the service has no ServiceDll pointing at qmgr.dll. Nothing can transfer because nothing started. |
A code in the 0x8020xxxx range, or 0x80d05001 | Site 2 — a genuine transfer fault | BITS and Delivery Optimization have their own facilities. Seeing BG_E_ or DO_E_ means the transfer layer really is the culprit — and it also means your fault is not one of our two codes. |
Failed to find file:, CSI Payload Corrupt or CBS MUM Missing in CBS.log | Site 3 — CBS payload resolution | Download was fine. A file a manifest references is absent from the package or the component store. |
CSI Manifest Corrupt or HRESULT_FROM_WIN32(ERROR_INVALID_DATA) in CBS.log | Site 4 — CBS manifest or catalog parse | The file is present but unreadable as a manifest or catalog. Corruption inside the component store itself. |
Either code beside Agent or ProtocolTalker during a scan, on a WSUS-managed device | Site 5 — scan and metadata fetch | Wrong or unreachable WUServer. The device is healthy; the path to the catalog is not. Test with iuident.cab. |
| Code appears only in Settings, or in an Intune or ConfigMgr report, with nothing in either log | Indeterminate — do not act | A relayed HRESULT with its raise site stripped. Reproduce with logging in place before choosing a fix. |
Step 5 — if site 5 is in play, read the policy before blaming the client
Site 5 failures are configuration, not corruption, and Microsoft documents the configuration in one key. State the parent once:
| Value | Meaning | What to look for |
|---|---|---|
WUServer | REG_SZ. Sets the WSUS server by HTTP name, for example http://IntranetSUS. | Present but unreachable, or pointing at a decommissioned server — a textbook site 5 file-not-found. Confirm it resolves and serves from the client, not from your desk. |
WUStatusServer | REG_SZ. Sets the statistics server by HTTP name. Normally identical to WUServer. | A mismatch after a migration. Reporting fails while scanning appears healthy, or the reverse. |
TargetReleaseVersion | Set to 1 to pin the device to a named Windows release. | Enabled with no valid partner value, or enabled years ago and forgotten. Governs which feature update the scan will even consider. |
TargetReleaseVersionInfo | The release the device is pinned to, e.g. 24H2. | Compare against the installed DisplayVersion. On the lab device this read 24H2 while the OS was really on 25H2 — an overtaken pin. Harmless in itself, but the pin no longer describes reality, and anyone reasoning from it reasons wrongly. |
UseWUServer (in the AU subkey) | Under ...\WindowsUpdate\AU. Set to 1 to point Automatic Updates at WUServer instead of the Microsoft service. | The presence or absence of the whole AU subkey is your management-model fingerprint. On the WUfB-managed lab device the subkey was absent entirely; a legacy-AU device looks the opposite. Chasing a WSUS fix on a device with no AU subkey is chasing nothing. |
ProductName. On the lab device — genuinely Windows 11 Enterprise, DisplayVersion 25H2, build 26200.9168 — the ProductName value still reads "Windows 10 Enterprise". Any script branching its update logic on ProductName silently takes the wrong path and reports a fault that is not there. Use CurrentBuild (22000 or higher) or DisplayVersion. Related: this device's servicing stack was 10.0.26100.9156 on a 26200 build. That skew is normal and is not evidence of anything.Step 6 — corroborate against the event log
Events tell you how far down the pipeline the update actually travelled, which narrows the site independently of any log parsing. Channel:
| Event ID | Message | What it tells you |
|---|---|---|
| 26 | Windows Update successfully found N updates | Scan completed, metadata fetched and parsed. Site 5 eliminated for this cycle. Observed on the lab device. |
| 41 | An update was downloaded | Transfer completed. Site 2 eliminated. If your error follows a 41, it is a servicing problem, not a download problem — so stop re-downloading. Observed on the lab device. |
| 2 (Setup log, not this channel) | Package <KB> was successfully changed to the Staged state | CBS accepted and staged the package, so payload resolution got far enough. A later failure points at install time rather than at site 3. Observed on the lab device in the Setup log. |
Used for elimination rather than confirmation, these are fast. A 26, then a 41, then a Setup 2, and then 0x80070002, leaves exactly one place to look.
Step 7 — check service state, and do not panic at the obvious
That baseline was captured read-only from a live corporate 25H2 device and every state in it is correct. Engineers reliably see trustedinstaller stopped, conclude the servicing stack is broken, and set it to Automatic — which fixes nothing and slightly degrades boot.
The fix: five branches, five different repairs
Only now, with a site identified, is a fix a decision rather than a guess.
Site 1, agent datastore. This is the branch the reset was designed for, and here it is correct. Microsoft's own manual procedure stops bits, wuauserv and cryptsvc, then renames SoftwareDistribution\DataStore, SoftwareDistribution\Download and System32\catroot2 to *.BAK. Note that it renames. Renaming preserves the old datastore for post-mortem at zero cost, and the blunter documented alternative — rd /s /q %systemroot%\SoftwareDistribution — does not.
Site 2, BITS. If the Parameters key is missing, restore it so ServiceDll points at %SystemRoot%\System32\qmgr.dll and start the service. Clearing SoftwareDistribution will not help, because nothing was ever downloaded. If instead you are seeing real BG_E_ codes, the fault is in the transfer path — proxy range-request support, inspection appliances, disk — and re-downloading into unchanged conditions simply reproduces it. Microsoft's mitigation for 0x8007000D is "try to redownload"; that is right for a one-off corruption and useless for a systematic one. Two identical failures on the same payload means stop retrying and go look at the path.
Site 3, CBS payload resolution. SoftwareDistribution is irrelevant — the payload arrived intact. The missing file is in the package or the component store, so this is a component-store repair against a known-good source: DISM /Online /Cleanup-Image /ScanHealth to assess, then /RestoreHealth, with an explicit /Source when the device is WSUS-managed and cannot reach Windows Update for replacement files. Check %WINDIR%\Logs\Dism\dism.log afterwards, not just the exit code.
Site 4, CBS manifest integrity. Also a component-store repair, but with a materially lower success rate — the thing that would supply a replacement manifest is the servicing stack that cannot read manifests. Expect to need an explicit source, and expect an in-place upgrade to be the honest answer more often than for site 3.
Site 5, scan and metadata. No file on the device needs touching. Fix WUServer, fix the proxy, fix the inspection rule that mangles cabinet downloads. Resetting SoftwareDistribution here produces the most demoralising outcome in the matrix: the reset appears to work, the first scan re-fetches metadata through the same broken path, the same code returns, and you conclude the device is beyond repair.
Why the SoftwareDistribution reset has such a reputation
It genuinely fixes site 1, and it genuinely papers over a transient site 2 transfer failure. That is roughly one branch in five — a hit rate high enough to become folklore, low enough to waste a great deal of time.
What makes it actively harmful is the cost of a miss. The folder holds the agent's datastore and the in-flight payload: the evidence for sites 1 and 2, gone. Then the reset fails, because the fault was in site 3, 4 or 5. Now you are diagnosing a subsystem whose evidence you deleted, and the next fix is chosen even more blindly than the first.
sfc /scannow as a reflex. SFC validates protected system files against the component store. If your fault is site 4 — a corrupt manifest in that very store — you are asking a damaged reference to validate itself, and a clean result means nothing. If your fault is site 1, 2 or 5, SFC is inspecting a subsystem that was never involved. It is a reasonable step once CBS has been implicated by name in CBS.log, and close to worthless before that.Proof it worked: the events that close the loop
"The error is gone" is not proof. The scan may not have run, the update may have been superseded, or the failure may be waiting on its next attempt. Prove the pipeline completed, leg by leg.
Those KB numbers and the service baseline above are real, read from the lab device. The four-leg sequence — scan, download, stage, install — is the proof, because each leg clears one or two of the five sites.
Then re-run Get-WindowsUpdateLog to a new file and confirm your code is absent from the window after the fix. Because the log is a static snapshot, you can diff it against your step-2 baseline and see the change directly. That is a far stronger claim than a green tick in Settings.
0x80070002 or 0x8007000D without a component tag from WindowsUpdate.log or a matching line from CBS.log. It reshapes the queue within a week, because the codes stop being one problem with five contradictory fixes and become five problems each with one.Both codes will appear forever. They are the two most generic failure modes in computing — the file was not there, and the bytes were wrong — and every layer of the update pipeline opens files and parses bytes.
What changes is what you do in the first five minutes. Decode the code, merge the log, read the component tag, and let the surrounding context name the subsystem. The fix is easy once you know which one it is, and unknowable until you do.
References
- System Error Codes (0-499) (WinError.h) - the canonical definitions:
2 (0x2) ERROR_FILE_NOT_FOUND"The system cannot find the file specified." and13 (0xD) ERROR_INVALID_DATA"The data is invalid." - [MS-ERREF]: HRESULT - the bit layout, the Facility field as "an indicator of the source of the error", and
FACILITY_WIN32= 7, "reserved to map undecorated error codes into HRESULTs." - HRESULT_FROM_WIN32 macro (winerror.h) - "Maps a system error code to an HRESULT value", with the
0x0000FFFFmask andFACILITY_WIN32shift that produce the0x8007prefix. - Windows Update error code list by component - the
WU_E_tables broken out by subsystem, and the source of the component vocabulary used above. Cited chiefly for what it does not contain: no row for either of our codes. - Common Windows Update errors - the
0x8007000Drow:ERROR_INVALID_DATA, "Indicates data that isn't valid was downloaded or corruption occurred", mitigation "Try to redownload the update, and then start the installation." - Troubleshoot Windows Update Error 0x80070002 - the dedicated article, the
Failed to find file: ... [HRESULT = 0x80070002 - ERROR_FILE_NOT_FOUND]line, theFACILITY_NTWIN32CSI excerpt, and theC:\Windows\Logs\CBS\CBS.logpath with itsCBSpersistrollover. - Fix Windows Update errors - the "Common corruption errors" table listing both
0x80070002and0x8007000D, plus theCSI Payload Corrupt,CBS MUM MissingandCSI Manifest Corruptmarkers used to separate site 3 from site 4. - Error 0x8007000d at Startup After You Install a Windows Update - the rollback symptom and the
HRESULT_FROM_WIN32(ERROR_INVALID_DATA) ... [gle=0x8007000d]log shape. - Troubleshoot issues with WSUS client agents - the site 2 finding:
ERROR_FILE_NOT_FOUND 0x80070002= "The Parameters key is missing", with the requiredServiceDll=%SystemRoot%\System32\qmgr.dll. AlsoBG_E_INSUFFICIENT_RANGE_SUPPORT,BG_E_MISSING_FILE_SIZE, theiuident.cabreachability test, and BITS's role in WSUS. - BITS Return Values - the
Bitsmsg.hconstants. Establishes that genuine BITS faults carry their own0x8020xxxxfacility rather than0x8007xxxx. - Additional resources for Windows Update - the official reset: stop
bits,wuauserv,cryptsvc, then renameDataStore,Downloadandcatroot2to*.BAK; plus the blunterrd /s /q %systemroot%\SoftwareDistributionform. - Configure Windows Update for Business - the documented
WUServerandWUStatusServervalues under theWindowsUpdatepolicy key, andUseWUServerunder theAUsubkey. - Windows Update log files - the log inventory: ETW traces in
C:\Windows\Logs\WindowsUpdate,CBS.login%systemroot%\Logs\CBSwhich "provides insight on the update installation part in the servicing stack",%WINDIR%\SoftwareDistribution\Datastore\Datastore.edb, and the USO.etlfiles. - Get-WindowsUpdateLog - "Windows Update no longer directly produces a WindowsUpdate.log file", the
-LogPathdefault of "WindowsUpdate.log in the Desktop folder of the current user", and the static-snapshot behaviour. - How Windows Update works - "Windows Update downloads manifest files and provides them to the arbiter", and Windows Update's use of Delivery Optimization.