Skip to content

extract_zip() missing strip-components/wrapper-folder handling — causes silent extraction failures on Windows (e.g. flm:npu) #2856

Open

Description

@johnlockejrr

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

  1. On a Windows machine, run lemonade backends install flm:npu.
  2. Observe Error: Failed to extract archive: <path>.
  3. 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" -NoNewline

After this, lemonade backends correctly reports flm npu installed v0.9.46.

Suggested Fix

  1. Give extract_zip() the same wrapper-folder detection/stripping logic
    extract_tarball() already has (reuse compute_tarball_strip_components()
    against the zip's file listing).
  2. Surface the captured tar/Expand-Archive stderr (the output
    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

  1. added
    engine::flmFastFlowLM backend (NPU); multi-modal LLM/ASR/embeddings/reranking
    on Jul 30, 2026
  2. joshuacox commented on Oct 9, 2026

    @joshuacox
    Contributor

    I'll take this one. extract_zip() needs the same wrapper-folder strip treatment extract_tarball() already has — sweet symmetry. PR incoming, covering the Windows native-tar path, the PowerShell fallback, and unzip on Unix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingengine::flmFastFlowLM backend (NPU); multi-modal LLM/ASR/embeddings/reranking

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions