[Bug] Enabling Virtual Machine Platform / WSL makes the VM unbootable and the image re-installs Windows (data loss) — VMX: Y, image 6.05 / QEMU 11.1.0
What version of WinBoat are you running?
0.9.2 (Podman runtime, packaged on NixOS)
Your Environment
- Host: NixOS 26.11, kernel 7.2.5, Intel i9-13900H,
/sys/module/kvm_intel/parameters/nested = Y - Image:
ghcr.io/dockur/windows:6.05(baseqemux/qemu:7.48, QEMU 11.1.0 — pinned in its Dockerfile) - Windows 11, latest build, freshly downloaded by the image on 2026-09-14
- Compose carries
VMX: "Y"(WinBoat never exposes this — it must be hand-added or injected by patching WinBoat's compose template)
Steps to Reproduce
- Run WinBoat with
VMX: "Y"— Windows itself installs and runs perfectly - Inside Windows, enable Virtual Machine Platform + Windows Subsystem for Linux
- Reboot → Windows fails to boot (recovery /
SrtTrail.txtloop) - On the following container start the dockur image decides the disk is unusable and re-installs Windows from scratch: it re-downloads the Win11 ISO ("Requesting Windows 11 from the Microsoft servers...") and recreates
data.img(200 GB). The previous installation and everything on it is gone.
Expected Behavior
VMP + WSL enable, reboot, WSL2 works.
Current Behavior
Feature enablement bricks the next boot, and the recovery path is catastrophic: the image wipes and re-installs Windows. Fully reproducible — every variant below ended the same way.
What I already tried (all on 0.9.2 / image 6.05 / QEMU 11.1.0; all ended in the same failure)
| # | Configuration | Result |
|---|---|---|
| 1 | VMX: "Y" only (host CPU model, image default hv_passthrough) |
VMP+WSL → reboot unbootable → image re-installs Windows |
| 2 | Same, with VMX: "Y" injected at source level via a Nix overlay patching WinBoat's compose template (runtime args identical) |
identical |
| 3 | HV: "Y" + VMX: "N" (control) |
Windows runs stable, WSL2 structurally impossible (no VT-x exposed) — this is my day-to-day config |
| 4 | VMX: "Y", HV: "Y", CPU_MODEL: "Broadwell-noTSX-IBRS", CPU_FLAGS: "hypervisor=off,vmx=on,mpx=off,hv-time=on,hv-relaxed=on,hv-vapic=on,hv-spinlocks=0x1fff", ADAPTER: "e1000e" (the dockur/windows #1191 recipe translated to the current image's env knobs) |
First start after the change fails to boot; the next start re-installs Windows. Caveats: HV: "Y" keeps hv_passthrough active, which per QEMU docs overrides the explicit hv-* flags, so this was not a faithful reproduction of #1191; the OS had also been installed under -cpu host before the model switch |
| 5 | Enabling Hyper-V directly instead of VMP/WSL | same: reboot → re-install |
Baseline / regression notes
My previous setup was WinBoat 0.8.x from nixpkgs → image 5.07 (base qemux/qemu:7.21, QEMU 10.0.x era) with VMX: "Y" auto-injected by the same overlay. Windows ran stably there with VMX exposed. To be precise about what "worked" means: my archived config repo records that WSL2 was never smoke-tested end-to-end on that stack, so I cannot claim WSL2 worked on 0.8.x. What is established: the destructive failure (enable → unbootable → image wipes the disk) is what I hit on 0.9.2 / image 6.05 / QEMU 11.1.0 + the latest Win11 build.
Version matrix (verified from tagged Dockerfiles / release notes):
| WinBoat | dockur/windows | qemux/qemu base | QEMU |
|---|---|---|---|
| 0.8.x | 5.07 | 7.21 | 10.0.x era |
| 0.9.0–0.9.1 | 5.14 | 7.29 | 10.0.x |
| 0.9.2 | 6.05 | 7.48 | 11.1.0 |
Analysis (with sources)
- dockur's documented pattern:
VMX: "Y"is the supported knob for nested virtualization, off by default because exposed VMX crashes Windows boot after certain updates — https://github.com/dockur/windows/issues/705 (the reason VMX defaulted off), maintainer comments in https://github.com/dockur/windows/issues/778 and https://github.com/dockur/windows/issues/917, https://github.com/dockur/windows/issues/1350. My case is the boot-crash side of that catch-22, not the "VMX missing" side. - QEMU docs classify
hv-passthrough(the image's default enlightenments mode) as a debugging/development feature, not recommended in production, which overrides every otherhv-*flag and blocks migration: https://www.qemu.org/docs/master/system/i386/hyperv.html - QEMU upstream #3345 documents a
hv_passthrough-sensitivity regression (SynIC unit tests) bisected inside the QEMU 10.2/11 development range — evidence that passthrough behavior is not stable across the QEMU 10→11 boundary I jumped: https://gitlab.com/qemu-project/qemu/-/work_items/3345 - QEMU docs also state nested Hyper-V needs
hv-stimer-direct; Microsoft supports WSL2 in a VM only with nested virtualization exposed: https://learn.microsoft.com/en-us/windows/wsl/faq - I found no existing report tying QEMU 11.1 specifically to this failure — whether QEMU 11.1.0 or the newer Windows build is the operative variable needs an A/B test (below).
Not yet tried (next steps on my side)
- Faithful #1191 recipe with
HV: "N"so the explicithv-*flags actually take effect (plushv-synic/hv-stimer/hv-stimer-directper QEMU's nested-Hyper-V docs), on a fresh Windows install created under the named CPU model rather than switched mid-life. - A/B: pin the image to
5.14(QEMU 10.0.x) with the same latest Win11 build andVMX: "Y"— isolates QEMU 11.1 vs Windows-build as the trigger.
Ask
- Has anyone reproduced enable-VMP/WSL → unbootable → image re-installs Windows (data loss) on 0.9.2 / 6.05 / QEMU 11.1?
- Should the image distinguish "broken but installed Windows" from "no installation" before recreating
data.img? Right now a failed feature enable escalates to full data loss — that seems worth a guard on the qemus/qemu or dockur side. - WinBoat never surfaces
VMX/CPU_MODEL/CPU_FLAGS/HV— users must hand-edit the compose (and re-do it whenever the file is regenerated). Would you consider exposing a nested-virtualization toggle and/or CPU overrides in the settings UI? - If the A/B confirms QEMU 11.1 +
hv_passthroughas the trigger, the fix likely belongs in qemus/qemu's defaultHV_FEATURES— happy to cross-report with this data.
Happy to run the remaining experiments and report results.
Note: researched and compiled with AI assistance; version/arg facts were verified against the running container, tagged Dockerfiles and release notes; the tried-configurations table is extracted verbatim from my session logs.
Source: TibixDev/winboat