Warn the user if VMP is not installed when create instance fails (#41357)
In some rare cases, the VirtualMachinePlatform feature could be left in a broken state, potentially by Windows updates. Where the WSL VM boots normally but hvsockets do not work. Resulting in HCS_E_CONNECTION_TIMEOUT. And it could be resolved by re-enabling the feature. As shown in #41346 This PR adds a VMP component check after a create instance failure. And warns the user if VMP is not enabled. To help the user potentially solving the failure. This PR also renames the old user message to better reflect its content. And uses its name for this new warning. This PR also adds the check to the installer step. So, it checks both services and the component when deciding if the component should be installed.
Feng Wang committed
Aug 18, 2026 at 11:12 UTC
1e14a49bc4ccbb24083cbe8bfe7f8566db297013
6 files changed
+56
-6
localization/strings/en-US/Resources.resw
+5
-1
@@ -960,10 +960,14 @@ Falling back to NAT networking.</value>
960
<value>Failed to launch the localhost relay process. Error: {}</value>
961
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
962
</data>
963
- <data name="MessageVirtualMachinePlatformNotInstalled" xml:space="preserve">
963
+ <data name="MessageVirtualMachinePlatformRequiredForNetworking" xml:space="preserve">
964
<value>Failed to start virtual networking - please install the optional component Virtual Machine Platform by running: wsl.exe --install --no-distribution</value>
965
<comment>{Locked="--install "}{Locked="--no-distribution"}Command line arguments, file names and string inserts should not be translated</comment>
966
</data>
967
+ <data name="MessageVirtualMachinePlatformNotInstalled" xml:space="preserve">
968
+ <value>Virtual Machine Platform is not enabled. WSL 2 may not work correctly. To enable it, run: wsl.exe --install --no-distribution</value>
969
+ <comment>{Locked="WSL 2"}{Locked="wsl.exe"}{Locked="--install "}{Locked="--no-distribution"}Command line arguments, file names and string inserts should not be translated</comment>
970
+ </data>
971
<data name="MessageNetworkInitializationFailedFallback2" xml:space="preserve">
972
<value>Failed to configure network (networkingMode {}), falling back to networkingMode {}.</value>
973
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
src/windows/common/WslInstall.cpp
+17
@@ -19,6 +19,7 @@ Abstract:
19
#include "Distribution.h"
20
#include "HandleConsoleProgressBar.h"
21
#include "svccomm.hpp"
22
+#include "WmiService.h"
23
24
extern HINSTANCE g_dllInstance;
25
@@ -251,6 +252,22 @@ void WslInstall::InstallOptionalComponents(const std::vector<std::wstring>& comp
252
wsl::windows::common::registry::WriteString(key.get(), nullptr, nullptr, wsl::shared::string::Join(installedComponents, L',').c_str());
253
}
254
255
+bool WslInstall::IsOptionalComponentInstalled(LPCWSTR component)
256
+{
257
+ constexpr int32_t c_enabled = 1;
258
+
259
+ wsl::core::WmiService service(L"ROOT\\CIMV2");
260
+ wsl::core::WmiEnumerate optionalFeatures(service);
261
+ const auto query = std::format(L"SELECT InstallState FROM Win32_OptionalFeature WHERE Name = '{}'", component);
262
+ const auto& results = optionalFeatures.query(query.c_str());
263
+ const auto result = results.begin();
264
+ THROW_HR_IF_MSG(HRESULT_FROM_WIN32(ERROR_NOT_FOUND), result == results.end(), "Optional component not found: %ls", component);
265
+
266
+ int32_t installState{};
267
+ THROW_HR_IF_MSG(E_UNEXPECTED, !result->get(L"InstallState", &installState), "Invalid optional component state: %ls", component);
268
+ return installState == c_enabled;
269
+}
270
+
271
std::pair<std::wstring, GUID> WslInstall::InstallModernDistribution(
272
const ModernDistributionVersion& distribution,
273
const std::optional<ULONG>& version,
src/windows/common/WslInstall.h
+2
@@ -49,6 +49,8 @@ public:
49
50
static DWORD InstallOptionalComponent(LPCWSTR component, bool consoleOutput);
51
52
+ static bool IsOptionalComponentInstalled(LPCWSTR component);
53
+
54
static std::pair<std::wstring, GUID> InstallModernDistribution(
55
const wsl::windows::common::distribution::ModernDistributionVersion& distribution,
56
const std::optional<ULONG>& version,
src/windows/common/wslutil.cpp
+15
-4
@@ -22,6 +22,7 @@ Abstract:
22
#include "ConsoleProgressBar.h"
23
#include "ExecutionContext.h"
24
#include "MsiQuery.h"
25
+#include "WslInstall.h"
26
27
using winrt::Windows::Foundation::Uri;
28
using winrt::Windows::Management::Deployment::DeploymentOptions;
@@ -1348,10 +1349,20 @@ bool wsl::windows::common::wslutil::IsVirtualMachinePlatformInstalled()
1349
{
1350
// Note for Windows 11 22H2 and above builds: If hyper-v is installed but VMP platform isn't, HNS and vmcompute are
1351
// available but calls to HNS will fail if vfpext isn't installed.
1351
- return wsl::windows::common::helpers::IsServicePresent(L"HNS") &&
1352
- wsl::windows::common::helpers::IsServicePresent(L"vmcompute") &&
1353
- (helpers::GetWindowsVersion().BuildNumber < helpers::WindowsBuildNumbers::Nickel ||
1354
- wsl::windows::common::helpers::IsServicePresent(L"vfpext"));
1352
+ if (!wsl::windows::common::helpers::IsServicePresent(L"HNS") || !wsl::windows::common::helpers::IsServicePresent(L"vmcompute") ||
1353
+ (helpers::GetWindowsVersion().BuildNumber >= helpers::WindowsBuildNumbers::Nickel &&
1354
+ !wsl::windows::common::helpers::IsServicePresent(L"vfpext")))
1355
+ {
1356
+ return false;
1357
+ }
1358
+
1359
+ try
1360
+ {
1361
+ return WslInstall::IsOptionalComponentInstalled(WslInstall::c_optionalFeatureNameVmp);
1362
+ }
1363
+ CATCH_LOG()
1364
+
1365
+ return true;
1366
}
1367
1368
wil::unique_handle wsl::windows::common::wslutil::OpenCallingProcess(_In_ DWORD access)
src/windows/service/exe/LxssUserSession.cpp
+16
@@ -17,6 +17,8 @@ Abstract:
17
#include "LxssUserSession.h"
18
#include "LxssInstance.h"
19
#include "LxssSecurity.h"
20
+#include "notifications.h"
21
+#include "WslInstall.h"
22
#include "WslCoreInstance.h"
23
#include "resource.h"
24
#include <winrt\Windows.ApplicationModel.Background.h>
@@ -2737,6 +2739,20 @@ std::shared_ptr<LxssRunningInstance> LxssUserSessionImpl::_CreateInstance(_In_op
2739
catch (...)
2740
{
2741
result = wil::ResultFromCaughtException();
2742
+
2743
+ if (version == LXSS_WSL_VERSION_2)
2744
+ {
2745
+ try
2746
+ {
2747
+ if (!WslInstall::IsOptionalComponentInstalled(WslInstall::c_optionalFeatureNameVmp))
2748
+ {
2749
+ wsl::windows::common::notifications::DisplayOptionalComponentsNotification();
2750
+ EMIT_USER_WARNING(wsl::shared::Localization::MessageVirtualMachinePlatformNotInstalled());
2751
+ }
2752
+ }
2753
+ CATCH_LOG()
2754
+ }
2755
+
2756
throw;
2757
}
2758
}
src/windows/service/exe/WslCoreVm.cpp
+1
-1
@@ -682,7 +682,7 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
682
!wsl::windows::common::wslutil::IsVirtualMachinePlatformInstalled())
683
{
684
wsl::windows::common::notifications::DisplayOptionalComponentsNotification();
685
- EMIT_USER_WARNING(Localization::MessageVirtualMachinePlatformNotInstalled());
685
+ EMIT_USER_WARNING(Localization::MessageVirtualMachinePlatformRequiredForNetworking());
686
}
687
688
// Fall back to no networking.