ruvnet/ruflo · error · ExtractionError

zip extraction failed via both available extractors…

Error message

zip extraction failed via both available extractors. Expand-Archive: ${primaryMessage} — tar fallback: ${fallbackMessage}

What it means

The Windows .zip extraction path is two-stage: Expand-Archive first, then bsdtar `tar xf` as fallback (zip is not gzip-compressed, hence 'xf' and format sniffing). When BOTH fail, install throws ExtractionError concatenating the primary (PowerShell) and fallback (tar) messages. The two embedded messages are the diagnostic — together they tell you whether the problem is the archive itself (both fail on corruption) or the machine (PowerShell policy + missing tar.exe).

Solutions

  1. Split the message at the ' — tar fallback:' marker: fix the PowerShell half (execution policy / module path) or the tar half (install bsdtar / use Windows 10+).
  2. If both messages show corruption ('not a valid archive', 'unexpected end'), clear the installer work/cache dir and re-run for a fresh download.
  3. Verify the zip manually: right-click Extract-All or `tar -tf archive.zip` to see which stage is at fault.
  4. Free disk space and rule out AV locks on the extraction directory.

Example fix

# before: both extractors unavailable -> combined error, install aborts
# after: make ONE extractor healthy
PS> Set-ExecutionPolicy -Scope CurrentUser RemoteSigned   # fixes Expand-Archive
# or ensure C:\Windows\System32\tar.exe exists (Windows 10 1803+)  # fixes fallback
PS> claude-flow install
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight on Windows before proxy install:
const extractors = [expandArchiveWorks, tarAvailable].map(f => f()).filter(Boolean).length;
if (extractors === 0) {
  throw new Error('no usable zip extractor: enable Expand-Archive (execution policy) or install tar.exe');
}
// >= 1 means the combined both-extractors failure cannot happen for environment reasons; only archive corruption remains.

Type guard

function isBothExtractorsError(e: unknown): e is Error {
  return e instanceof Error && e.message.startsWith('zip extraction failed via both available extractors');
}

Try / catch

for (let attempt = 1; ; attempt++) {
  try {
    return await installProxyBinary({ version });
  } catch (e) {
    if (attempt < 3 && isBothExtractorsError(e)) {
      await cleanWorkDir(); // both extractors failing usually means a corrupt download — fetch fresh
      continue;
    }
    if (isBothExtractorsError(e)) {
      const [, primary, fallback] = e.message.split(/ — tar fallback: /);
      throw new Error(`install blocked: fix extractor environment. PowerShell: ${primary}. tar: ${fallback}`);
    }
    throw e;
  }
}

Prevention

When it happens

Trigger: A corrupted/truncated .zip download fails in both extractors; or a stripped-down Windows environment where Expand-Archive is blocked (execution policy) AND tar.exe is absent/older-than-Windows-10 — both stages then fail for different reasons, and both messages appear in the thrown error.

Common situations: Hardened Windows Server images with Restricted execution policy and no bsdtar; interrupted proxy binary downloads (network dropped mid-asset); CI Windows runners with damaged PowerShell module paths plus no tar on PATH; destination disk full so every extractor exits non-zero.

Related errors


AI-assisted analysis of ruvnet/ruflo@29f048fc3b (2026-08-18). Data as JSON: /api/errors/40b7870f7b89ecbe. Report an issue: GitHub.

Appendix: source

Thrown at v3/@claude-flow/cli/src/proxy/install.ts:99

 */
export async function extractArchive(archivePath: string, extractDir: string, ext: 'zip' | 'tar.gz'): Promise<void> {
  fs.mkdirSync(extractDir, { recursive: true });

  if (ext === 'tar.gz') {
    await extractWithTar(archivePath, extractDir, 'xzf');
    return;
  }

  try {
    await extractWithPowerShell(archivePath, extractDir);
  } catch (primary) {
    const primaryMessage = primary instanceof Error ? primary.message : String(primary);
    try {
      // 'xf', not 'xzf' — a zip is not gzip-compressed; bsdtar sniffs the format.
      await extractWithTar(archivePath, extractDir, 'xf');
    } catch (fallback) {
      const fallbackMessage = fallback instanceof Error ? fallback.message : String(fallback);
      throw new ExtractionError(
        `zip extraction failed via both available extractors. Expand-Archive: ${primaryMessage} — tar fallback: ${fallbackMessage}`,
      );
    }
  }
}

export interface InstallOptions {
  version: string;
  log?: (line: string) => void;
}

export interface InstallResult {
  version: string;
  binaryPath: string;
  sha256: string;
}

/**

View on GitHub (pinned to 29f048fc3b)