Repository navigation
extract_zip() missing strip-components/wrapper-folder handling — causes silent extraction failures on Windows (e.g. flm:npu) #2856
Description
Platform
Windows
Lemonade Version
11.5.1
GPU / APU Model
AMD gfx1151/Ryzen AI MAX+ 392
Component
Other / Not sure
Bug Description
lemonade backends install flm:npu fails on Windows with:
Error: Failed to extract archive: C:\Users\<user>\AppData\Local\Temp\flm_npu_v0.9.46_fastflowlm_0.9.46_windows_amd64.zip
Reproduced on gfx1151 (Ryzen AI MAX+ 392 / Radeon 8060S, Strix Halo) on Windows 11.
Root Cause
In src/cpp/server/utils/platform/archive_windows.cpp, extract_zip() has
no strip-components / wrapper-folder handling at all — unlike
extract_tarball(), which computes a strip value via
compute_tarball_strip_components() before extracting. extract_zip()
just runs tar -xf (or Expand-Archive as fallback) straight into the
staging dir:
bool extract_zip(const std::string& zip_path, const std::string& dest_dir, ...) {
fs::create_directories(dest_dir);
... // tar -xf or Expand-Archive — no wrapper-folder stripping
}The FastFlowLM release zip
(fastflowlm_0.9.46_windows_amd64.zip) has its contents nested under a
wrapper folder (fastflowlm-windows-<commit-hash>/). After extraction,
the code checks for flm.exe directly under the install dir, doesn't find
it (it's one level too deep, inside the wrapper folder), and the generic
extraction-failure path fires:
if (!extract_archive(zip_path, staging_dir, spec.log_name())) {
throw std::runtime_error("Failed to extract archive: " + zip_path);
}Additionally, the actual tar/Expand-Archive stderr output (captured in
the output variable inside extract_zip) is only logged at DEBUG
level via LOG(ERROR, backend_name), and even with log_level: debug set,
the log shows extraction starting (Extracting ZIP with native tar to ...\npu.staging) and then nothing further before the CLI's generic error
appears — no success or failure line for this specific step, making the
real cause hard to diagnose without manually re-extracting the archive.
Steps to Reproduce
- On a Windows machine, run
lemonade backends install flm:npu. - Observe
Error: Failed to extract archive: <path>. - Manually extract the same zip (
Expand-Archive) and inspect the
result — contents are nested under a wrapper folder
(fastflowlm-windows-<hash>/) rather than sitting at the top level.
Confirmed Workaround
Manually extract the zip and flatten the wrapper folder into the expected
install path (<cache>\bin\flm\npu\), merging any pre-existing
subfolders (e.g. xclbins\) rather than overwriting — Move-Item errors
on folder-name collisions when merging directories, so robocopy /E or
Explorer's merge-copy is needed instead:
$dest = "<cache>\bin\flm\npu"
Expand-Archive -LiteralPath fastflowlm_0.9.46_windows_amd64.zip -DestinationPath staging -Force
robocopy "staging\fastflowlm-windows-<hash>" $dest /E /R:2 /W:2
Set-Content -Path "$dest\version.txt" -Value "v0.9.46" -NoNewlineAfter this, lemonade backends correctly reports flm npu installed v0.9.46.
Suggested Fix
- Give
extract_zip()the same wrapper-folder detection/stripping logic
extract_tarball()already has (reusecompute_tarball_strip_components()
against the zip's file listing). - Surface the captured
tar/Expand-Archivestderr (theoutput
variable) in the thrown exception message itself, not only at DEBUG log
level — the current message gives no actionable detail even with
verbose logging enabled.
Environment
- OS: Windows 11
- Hardware: AMD Ryzen AI MAX+ 392, Radeon 8060S (gfx1151), Strix Halo
- Lemonade version: 11.5.1
- Backend affected:
flm:npu(FastFlowLM v0.9.46) — likely affects any
zip-based backend whose release archive has a wrapper folder
Expected vs Actual Behavior
No response
Log Output
Additional Context
No response
Activity
joshuacox commentedon Oct 9, 2026
I'll take this one.
extract_zip()needs the same wrapper-folder strip treatmentextract_tarball()already has — sweet symmetry. PR incoming, covering the Windows native-tar path, the PowerShell fallback, and unzip on Unix.