{"record":{"id":"be74380e889e2b84","repo":"nextlevelbuilder/ui-ux-pro-max-skill","slug":"failed-to-extract-zip-error","errorCode":null,"errorMessage":"Failed to extract zip: ${error}","messagePattern":"Failed to extract zip: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/utils/extract.ts","lineNumber":22,"sourceCode":"import { promisify } from 'node:util';\nimport { tmpdir } from 'node:os';\nimport type { AIType } from '../types/index.js';\nimport { AI_FOLDERS } from '../types/index.js';\n\nconst execAsync = promisify(exec);\n\nconst EXCLUDED_FILES = ['settings.local.json'];\n\nexport async function extractZip(zipPath: string, destDir: string): Promise<void> {\n  try {\n    const isWindows = process.platform === 'win32';\n    if (isWindows) {\n      await execAsync(`powershell -Command \"Expand-Archive -Path '${zipPath}' -DestinationPath '${destDir}' -Force\"`);\n    } else {\n      await execAsync(`unzip -o \"${zipPath}\" -d \"${destDir}\"`);\n    }\n  } catch (error) {\n    throw new Error(`Failed to extract zip: ${error}`);\n  }\n}\n\nasync function exists(path: string): Promise<boolean> {\n  try {\n    await access(path);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nexport async function copyFolders(\n  sourceDir: string,\n  targetDir: string,\n  aiType: AIType\n): Promise<string[]> {\n  const copiedFolders: string[] = [];","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/nextlevelbuilder/ui-ux-pro-max-skill/blob/a38d04c3d5c298c851dbe5e6ee1965ee3de42cb5/cli/src/utils/extract.ts#L4-L40","documentation":"extractZip() shells out to the platform's unzip tool (Expand-Archive on Windows, the `unzip` binary elsewhere) and wraps any non-zero exit in a generic 'Failed to extract zip' error. It fires when the external command itself fails: the tool is missing, the archive is corrupt or not a real zip, or the path contains characters the shell command mangles.","triggerScenarios":"`uipro init` reaches the extraction step and: (1) the downloaded release.zip is an HTML error page or truncated because the download was interrupted; (2) on macOS/Linux the `unzip` binary is not installed (minimal containers like alpine node images); (3) a path with spaces/quotes breaks the interpolated shell string; (4) Expand-Archive is unavailable on old Windows PowerShell or the destination is locked.","commonSituations":"Running the installer inside a slim Docker image that lacks unzip; a proxy/CDN returning a 200 response with an error body; extracting into a directory the user cannot write; zip64 archives that some unzip builds cannot handle.","solutions":["Verify the downloaded file is a real zip: `file release.zip` or check its first bytes are 'PK'.","Install the missing tool: `apt-get install unzip` (Debian/Alpine: `apk add unzip`) on Linux, or confirm PowerShell 5+ on Windows.","Re-run the install on a stable network, or retry from a different network if the download was truncated.","If the temp path contains quotes/spaces, move the operation to a plain path (e.g. TMPDIR without spaces) or replace execAsync with a Node zip library such as yauzl/adm-zip that takes paths as arguments, avoiding shell interpolation entirely."],"exampleFix":"// before\nawait execAsync(`unzip -o \"${zipPath}\" -d \"${destDir}\"`);\n// after: no shell interpolation, no external binary\nimport AdmZip from 'adm-zip';\nnew AdmZip(zipPath).extractAllTo(destDir, true);","handlingStrategy":"validation","validationCode":"import { open } from 'node:fs/promises';\nimport { exec } from 'node:child_process';\n\nasync function isRealZip(path: string): Promise<boolean> {\n  const fh = await open(path, 'r');\n  try {\n    const buf = Buffer.alloc(2);\n    await fh.read(buf, 0, 2, 0);\n    return buf.toString('ascii') === 'PK';\n  } finally {\n    await fh.close();\n  }\n}\n\nfunction hasUnzip(): Promise<boolean> {\n  return new Promise(res => exec('unzip -v', err => res(!err)));\n}","typeGuard":null,"tryCatchPattern":"try {\n  await extractZip(zipPath, destDir);\n} catch (e) {\n  throw new Error(\n    `Extraction failed on ${process.platform}; zip valid=${await isRealZip(zipPath)}; ` +\n    `likely missing 'unzip' binary or corrupt download: ${(e as Error).message}`\n  );\n}","preventionTips":["Install unzip in Dockerfiles that run the CLI (apk add unzip / apt-get install -y unzip).","Validate the zip magic bytes ('PK') right after download, before extraction.","Prefer a pure-JS zip library (yauzl, adm-zip) to remove the external-binary dependency and shell-quoting risks entirely."],"tags":["cli","zip","shell","extraction","windows"],"backgroundTag":null,"analyzedSha":"a38d04c3d5c298c851dbe5e6ee1965ee3de42cb5","analyzedAt":"2026-08-14T18:51:02.321Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}