Warn the user if VMP is not installed when create instance fails - #41357
Conversation
There was a problem hiding this comment.
Pull request overview
This PR improves WSL 2 diagnostics and installation checks around the VirtualMachinePlatform (VMP) optional feature, aiming to better guide users when VM creation/initialization fails due to VMP being disabled or partially unavailable.
Changes:
- Adds a post-failure VMP feature-state check during WSL 2 instance creation and emits a user warning when VMP appears disabled.
- Refines/renames the networking-related VMP warning used during VM initialization fallback behavior.
- Extends the installer’s “missing optional components” detection by checking VMP via DISM feature state in addition to existing service-presence checks.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/windows/service/exe/WslCoreVm.cpp | Switches the networking fallback warning to a newly named string. |
| src/windows/service/exe/LxssUserSession.cpp | On WSL 2 instance creation failure, checks VMP state and emits a user warning/notification. |
| src/windows/common/WslInstall.h | Adds a new helper API to query whether an optional component is installed/enabled. |
| src/windows/common/WslInstall.cpp | Implements DISM-based feature-state query and uses it in missing-component detection. |
| localization/strings/en-US/Resources.resw | Adds a new string and repurposes an existing VMP-related string key. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| <data name="MessageVirtualMachinePlatformNotInstalled" xml:space="preserve"> | ||
| <value>Virtual Machine Platform is not enabled. WSL 2 may not work correctly. To enable it, run: wsl.exe --install --no-distribution</value> | ||
| <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> | ||
| </data> |
There was a problem hiding this comment.
A new localization change should update the old ones.
Blue (@OneBlue) . Could you please help confirm this? Thanks.
There was a problem hiding this comment.
Yes that's correct. Only the en-US version should be added in this PR
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
Suppressed comments (4)
localization/strings/en-US/Resources.resw:969
MessageVirtualMachinePlatformNotInstalledis being repurposed to a new meaning (“VMP is not enabled / WSL 2 may not work correctly”). Existing localized resource files still translate this key with the old networking-specific meaning (e.g.localization/strings/fr-FR/Resources.reswaround line 970 still says “Failed to start virtual networking…”), so non-en-US users will see an incorrect warning.
To keep translations correct, avoid changing the meaning of an existing resource key. Add a new resource key for this new warning (and update the new call site to use it), while keeping MessageVirtualMachinePlatformNotInstalled’s existing value/meaning stable (or keep using it for the networking failure path).
<data name="MessageVirtualMachinePlatformNotInstalled" xml:space="preserve">
<value>Virtual Machine Platform is not enabled. WSL 2 may not work correctly. To enable it, run: wsl.exe --install --no-distribution</value>
<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>
src/windows/service/exe/LxssUserSession.cpp:2740
- This warning emits
MessageVirtualMachinePlatformNotInstalled(), but that resource key historically meant “virtual networking failed; install VMP…”, and is already translated that way in many non-en-US .resw files (e.g. fr-FR/es-ES). With the updated en-US value, non-en-US users will see the old networking-related translation here.
Prefer introducing a new resource key for this new “VMP not enabled / WSL 2 may not work correctly” warning, and keep the existing key’s meaning stable to preserve translations.
if (!WslInstall::IsOptionalComponentInstalled(WslInstall::c_optionalFeatureNameVmp))
{
wsl::windows::common::notifications::DisplayOptionalComponentsNotification();
EMIT_USER_WARNING(wsl::shared::Localization::MessageVirtualMachinePlatformNotInstalled());
}
src/windows/common/WslInstall.cpp:278
IsOptionalComponentInstalled()throws if it can’t find/parse theState :line in DISM output. Since this is a best-effort diagnostic/helper (and is used in installer prereq detection), returning false with a log is safer than aborting the whole operation on an unexpected output format.
THROW_HR_MSG(E_UNEXPECTED, "Failed to parse optional component state: %ls", component);
src/windows/common/WslInstall.cpp:265
IsOptionalComponentInstalled()currently throws if DISM returns a non-zero exit code. This helper is used byCheckForMissingOptionalComponents()(invoked before elevation in the install flow), so throwing here can causewsl.exe --installto fail outright due to a transient DISM error instead of falling back to the existing service-based checks.
Consider treating DISM failures as “unknown/not installed” (log and return false) rather than throwing.
This issue also appears on line 277 of the same file.
const auto result = process.RunAndCaptureOutput();
THROW_HR_IF_MSG(
HRESULT_FROM_WIN32(result.ExitCode), result.ExitCode != ERROR_SUCCESS, "Failed to query optional component: %ls", component);
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
Suppressed comments (3)
localization/strings/en-US/Resources.resw:970
- MessageVirtualMachinePlatformNotInstalled is now being used for a different meaning than the existing translations in other locales (e.g. es-ES still translates it as the old “Failed to start virtual networking…” message). This will cause non-en-US users to see an incorrect/misleading warning. To avoid breaking existing translations, keep the existing key’s meaning stable (or leave it unused) and introduce a new resource key for the new “VMP is not enabled / WSL 2 may not work correctly” warning, then update the new call site(s) to use that new key.
<data name="MessageVirtualMachinePlatformNotInstalled" xml:space="preserve">
<value>Virtual Machine Platform is not enabled. WSL 2 may not work correctly. To enable it, run: wsl.exe --install --no-distribution</value>
<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>
</data>
src/windows/common/WslInstall.cpp:280
- IsOptionalComponentInstalled() throws on DISM failures/timeouts and on parse failures. This function is now called from CheckForMissingOptionalComponents() during install prerequisite checks, so a transient DISM error/timeout can cause wsl --install to fail early instead of proceeding (or treating the feature as missing). Consider making this a best-effort query that logs and returns false on failure.
std::wstring systemDirectory;
THROW_IF_FAILED(wil::GetSystemDirectoryW(systemDirectory));
const auto dismPath = std::filesystem::path(std::move(systemDirectory)) / L"dism.exe";
const auto commandLine = std::format(L"{} /Online /English /Get-FeatureInfo /FeatureName:{}", dismPath.native(), component);
src/windows/service/exe/LxssUserSession.cpp:2743
- This adds a DISM call (up to 30s timeout) on every WSL2 CreateInstance exception path before rethrowing. That can significantly delay unrelated failures and add extra noise. Since the motivating scenario is HCS_E_CONNECTION_TIMEOUT, consider gating the DISM query/warning on the specific failure HRESULT stored in
result.
if (version == LXSS_WSL_VERSION_2)
{
try
{
if (!WslInstall::IsOptionalComponentInstalled(WslInstall::c_optionalFeatureNameVmp))
| <data name="MessageVirtualMachinePlatformNotInstalled" xml:space="preserve"> | ||
| <value>Virtual Machine Platform is not enabled. WSL 2 may not work correctly. To enable it, run: wsl.exe --install --no-distribution</value> | ||
| <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> | ||
| </data> |
There was a problem hiding this comment.
Yes that's correct. Only the en-US version should be added in this PR
| std::wstring systemDirectory; | ||
| THROW_IF_FAILED(wil::GetSystemDirectoryW(systemDirectory)); | ||
|
|
||
| const auto dismPath = std::filesystem::path(std::move(systemDirectory)) / L"dism.exe"; |
There was a problem hiding this comment.
I don't think we want to add a dependency on parsing dism's output. It doesn't seem to be designed to be parsed by a program and I'd be worried that its format could change at some point.
The root cause of the associated problem seems to be a broken Windows installation where some of VMP was enabled, and some of it was broken. If we want to detect these kind of "broken OC state", I think the easiest would be to use something like DismGetFeatureInfo and look at its output. Sadly we don't have the ADK easily available so we'll have to manually load dismapi for it.
Once we have this implemented, we could add that call at the end of IsVirtualMachinePlatformInstalled(), so all existing calls will detect when VMP is in a bad state
Summary of the Pull Request
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 DISM check to the installer step. So, it checks both services and the component when deciding if the component should be installed.
PR Checklist
Detailed Description of the Pull Request / Additional comments
Validation Steps Performed
Tested locally by injecting a failure into create instance.

