ruvnet/ruflo · error · ExtractionError
tar extraction failed
Error message
tar extraction failed (exit ${result.exitCode}): ${result.stderr || result.stdout} What it means
During meta-proxy binary installation, .tar.gz (and zip-fallback) extraction shells out to `tar` through SafeExecutor (60s timeout, allowlist ['tar']). A non-zero exit code throws ExtractionError with the code plus tar's stderr/stdout. The archive was downloaded into a work directory first, so the failure is about extraction, not the download itself — typically a truncated/corrupt archive, missing tar binary, disk full, or permission problems on the extract directory.
Solutions
- Read the embedded stderr in the message — tar states the exact problem (corrupt gzip, permissions, space).
- Free disk space / fix permissions on the install work directory, then re-run install (it re-downloads).
- Ensure `tar` exists on PATH (Windows 10+ ships bsdtar; Linux/macOS always do; slim containers need the tar package added).
- If corruption is suspected, clear the installer's work/cache directory so a fresh archive is downloaded.
Example fix
# before: slim container without tar -> exit 127 -> ExtractionError FROM node:22-slim RUN claude-flow-proxy-install # after FROM node:22-slim RUN apt-get update && apt-get install -y tar && rm -rf /var/lib/apt/lists/* RUN claude-flow-proxy-install
Defensive patterns
Strategy: retry
Validate before calling
import { execFileSync } from 'node:child_process';
function tarAvailable(): boolean {
try { execFileSync('tar', ['--version'], { stdio: 'ignore' }); return true; } catch { return false; }
}
// Before triggering proxy install:
if (!tarAvailable()) throw new Error('tar not on PATH — install it (apt-get install tar / use Windows 10+) before proxy install'); Type guard
function isExtractionError(e: unknown): e is Error {
return e instanceof Error && /tar extraction failed \(exit \d+\)/.test(e.message);
} Try / catch
for (let attempt = 1; ; attempt++) {
try {
return await installProxyBinary({ version });
} catch (e) {
if (attempt < 3 && isExtractionError(e)) {
await cleanWorkDir(); // drop the possibly-truncated archive so the retry re-downloads
continue;
}
if (isExtractionError(e)) throw new Error(`proxy install failed after retries: ${e.message}`);
throw e;
}
} Prevention
- Verify tar exists in the runtime image before depending on proxy install.
- Ensure the install work directory is writable and has free space.
- Clean partial downloads between attempts — re-extracting the same corrupt archive always fails the same way.
When it happens
Trigger: install runs `tar xzf <archive> -C <extractDir>` and tar exits non-zero: gzip corruption from a partially downloaded asset ('unexpected end of file'), 'tar: command not found' variant (exit 127 via executor), no space left on device, read-only extract dir, or extraction exceeding the 60s SafeExecutor timeout on huge archives/slow disks.
Common situations: Flaky network producing truncated downloads; minimal Docker images (slim/distroless) without tar; CI runners with full disks; Windows boxes older than Windows 10 (no bsdtar); aggressive antivirus locking the archive mid-extraction on Windows.
Related errors
- Expand-Archive failed
- zip extraction failed via both available extractors…
- 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/48877b9bae574aae.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/proxy/install.ts:36
export class ExtractionError extends Error {
constructor(message: string) {
super(message);
this.name = 'ExtractionError';
}
}
function binaryNameInArchive(): string {
return process.platform === 'win32' ? 'meta-proxy.exe' : 'meta-proxy';
}
/** `tar` handles `.tar.gz` everywhere, and `.zip` via bsdtar on Windows 10+. */
async function extractWithTar(archivePath: string, extractDir: string, flags: 'xzf' | 'xf'): Promise<void> {
const { SafeExecutor } = await import('@claude-flow/security');
const exec = new SafeExecutor({ allowedCommands: ['tar'], timeout: 60_000 });
const result = await exec.execute('tar', [flags, archivePath, '-C', extractDir]);
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}`);
}View on GitHub (pinned to 29f048fc3b)