ruvnet/ruflo · error · ExtractionError
Expand-Archive failed
Error message
Expand-Archive failed (exit ${result.exitCode}): ${result.stderr || result.stdout} What it means
On Windows, .zip extraction uses PowerShell's Expand-Archive via SafeExecutor (allowlist powershell/powershell.exe, 60s timeout, paths single-quote-escaped). A non-zero exit throws ExtractionError with the code and PowerShell's stderr. Expand-Archive is a script module (Microsoft.PowerShell.Archive) resolved through module autoloading, so it fails when PowerShell's execution policy blocks scripts, the module is missing/damaged, or powershell.exe isn't reachable. In the normal flow this error is caught and bsdtar 'xf' is tried as fallback — you see this message alone only when extraction is invoked directly or you're tracing the primary failure embedded in the both-extractors error.
Solutions
- Read the embedded stderr — 'running scripts is disabled' points at execution policy.
- Allow the archive module: Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, or fix PSModulePath so Microsoft.PowerShell.Archive autoloads.
- Ensure the automatic fallback can work: keep Windows 10+ bsdtar (tar.exe) available — the installer already retries with `tar xf` when Expand-Archive fails, so a healthy tar makes this error invisible.
- Free disk/AV locks on the extract directory, then re-run install.
Example fix
# before: policy blocks the script module -> exit non-zero PS> claude-flow install # Expand-Archive failed ... # after PS> Set-ExecutionPolicy -Scope CurrentUser RemoteSigned PS> claude-flow install # Expand-Archive (or tar fallback) succeeds
Defensive patterns
Strategy: fallback
Validate before calling
import { execFileSync } from 'node:child_process';
function expandArchiveWorks(): boolean {
try {
execFileSync('powershell', ['-NoProfile', '-NonInteractive', '-Command',
'Get-Command Expand-Archive | Out-Null'], { timeout: 15_000, stdio: 'ignore' });
return true;
} catch { return false; }
}
// On Windows, before relying on zip extraction:
if (!expandArchiveWorks() && !tarAvailable()) throw new Error('no working zip extractor: fix execution policy or provide tar.exe'); Type guard
function isPowerShellExtractError(e: unknown): e is Error {
return e instanceof Error && e.message.startsWith('Expand-Archive failed (exit ');
} Try / catch
try {
await extractZip(archivePath, dir); // primary: Expand-Archive
} catch (primary) {
if (!isPowerShellExtractError(primary)) throw primary;
try {
await extractWithTar(archivePath, dir, 'xf'); // fallback: bsdtar sniffs zip format
} catch (fallback) {
throw new Error(`zip extraction exhausted: Expand-Archive: ${primary.message} — tar: ${fallback.message}`);
}
} Prevention
- Keep at least one extractor healthy on Windows: fix execution policy (RemoteSigned for CurrentUser) or guarantee tar.exe (Windows 10 1803+).
- Include Expand-Archive availability in your environment preflight on Windows images.
- Don't strip powershell.exe from images if you rely on .zip proxy installs — the allowlist names powershell/powershell.exe only.
When it happens
Trigger: powershell -NoProfile -NonInteractive -Command "Expand-Archive ..." exits non-zero: ExecutionPolicy Restricted blocking the Archive script module, PSModulePath broken so Microsoft.PowerShell.Archive can't autoload, PowerShell 7-only hosts where powershell.exe (5.1) is stripped, corrupted zip, or disk-full/locked destination.
Common situations: Hardened Windows images with Restricted execution policy; systems where PSModulePath was overwritten by other tooling; enterprises removing Windows PowerShell 5.1 in favor of pwsh (the allowlist names powershell/powershell.exe only); AV holding locks on extracted files.
Related errors
- zip extraction failed via both available extractors…
- tar extraction failed
- archive did not contain the expected binary at its root
- Previous Meta-Proxy .
- Rollback failed
AI-assisted analysis of ruvnet/ruflo@29f048fc3b (2026-08-18).
Data as JSON: /api/errors/7bcae8e663cc1fb0.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/proxy/install.ts:53
if (result.exitCode !== 0) {
throw new ExtractionError(`tar extraction failed (exit ${result.exitCode}): ${result.stderr || result.stdout}`);
}
}
/**
* Single-quoted literal paths (doubling any embedded single quote per
* PowerShell string-literal escaping) passed as ONE argv element to
* `-Command`. shell:false means no OS shell ever tokenizes this string —
* only powershell.exe's own parser does.
*/
async function extractWithPowerShell(archivePath: string, extractDir: string): Promise<void> {
const { SafeExecutor } = await import('@claude-flow/security');
const escape = (p: string) => p.replace(/'/g, "''");
const command = `Expand-Archive -LiteralPath '${escape(archivePath)}' -DestinationPath '${escape(extractDir)}' -Force`;
const exec = new SafeExecutor({ allowedCommands: ['powershell', 'powershell.exe'], timeout: 60_000 });
const result = await exec.execute('powershell', ['-NoProfile', '-NonInteractive', '-Command', command]);
if (result.exitCode !== 0) {
throw new ExtractionError(`Expand-Archive failed (exit ${result.exitCode}): ${result.stderr || result.stdout}`);
}
}
/**
* Extracts the archive via the OS's own tools — `tar` for `.tar.gz`
* (present on macOS/Linux/Windows 10+), PowerShell `Expand-Archive`
* specifically for `.zip` on Windows. Zero new archive-parsing dependency,
* matching this repo's existing taste for shelling out over adding a parser dep.
*
* `Expand-Archive` stays the PRIMARY `.zip` path — bsdtar's zip support is
* still not something to lean on by default. But `Microsoft.PowerShell.Archive`
* is a *script* module resolved through PowerShell's module autoloading, so it
* can fail for environment reasons entirely unrelated to the archive. Observed
* in the wild on a healthy Windows 11 box, from ruflo's own `-NonInteractive`
* child process:
*
* Expand-Archive : The 'Expand-Archive' command was found in the module
* 'Microsoft.PowerShell.Archive', but the module could not be loaded.View on GitHub (pinned to 29f048fc3b)