{"record":{"id":"add42de5e916f1fe","repo":"ruvnet/ruflo","slug":"archive-did-not-contain-the-expected-binary-at-its","errorCode":null,"errorMessage":"archive did not contain the expected binary at its root: ${binaryNameInArchive()}","messagePattern":"archive did not contain the expected binary at its root: (.+?)","errorType":"exception","errorClass":"ExtractionError","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/proxy/install.ts","lineNumber":153,"sourceCode":"      assetBytes: assets.archiveBytes,\n      assetFilename: assets.archiveFilename,\n    });\n    log(`Verified — sha256 ${sha256.slice(0, 16)}…`);\n\n    // fetchReleaseAssets's dev (gh) path already wrote the archive to workDir\n    // under archiveFilename; ensure it's there regardless of source so\n    // extraction always has a real file to operate on.\n    const archivePath = path.join(workDir, archiveFilename);\n    if (!fs.existsSync(archivePath)) {\n      fs.writeFileSync(archivePath, assets.archiveBytes);\n    }\n\n    const extractDir = path.join(workDir, 'extracted');\n    await extractArchive(archivePath, extractDir, releaseArchiveExtension(triple));\n\n    const extractedBinaryPath = path.join(extractDir, binaryNameInArchive());\n    if (!fs.existsSync(extractedBinaryPath)) {\n      throw new ExtractionError(`archive did not contain the expected binary at its root: ${binaryNameInArchive()}`);\n    }\n\n    // Defense in depth: confirm the extracted binary genuinely resolves\n    // inside extractDir (catches a symlink swap or similar), even though\n    // we only ever read one specific expected relative path, never an\n    // archive-listed one (so \"zip slip\" via arbitrary archive paths isn't\n    // reachable here in the first place).\n    const { PathValidator } = await import('@claude-flow/security');\n    const validator = new PathValidator({ allowedPrefixes: [extractDir] });\n    const validation = await validator.validate(extractedBinaryPath);\n    if (!validation.isValid) {\n      throw new ExtractionError(`extracted binary path failed validation: ${validation.errors.join('; ') || 'unknown'}`);\n    }\n\n    const finalPath = proxyBinaryPath();\n    fs.mkdirSync(path.dirname(finalPath), { recursive: true, mode: 0o700 });\n    const tmp = `${finalPath}.tmp`;\n    fs.copyFileSync(extractedBinaryPath, tmp);","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/ruvnet/ruflo/blob/29f048fc3b556f857cf2b126d2a84c19d2daa0d0/v3/@claude-flow/cli/src/proxy/install.ts#L135-L171","documentation":"After extracting the meta-proxy release archive, install checks that the expected binary (meta-proxy, or meta-proxy.exe on Windows) exists at the ROOT of the extraction directory. If it does not, it throws — meaning extraction 'succeeded' but the layout isn't what the installer expects: the release artifact nested the binary in a subfolder, the platform triple selected an archive with a different layout, or the archive was empty/not actually a binary release. A subsequent PathValidator check then guards against symlink tricks, but this error is purely 'the file isn't where it must be'.","triggerScenarios":"install downloads the asset for the detected platform triple and runs extractArchive, but the tarball's top level is e.g. 'meta-proxy-0.4.2-x86_64/bin/meta-proxy' instead of './meta-proxy'; or a release accidentally shipped sources only; or wrong-architecture asset (arm64 vs x64) with a different internal layout; or extraction silently extracting nothing (empty archive) while exiting 0.","commonSituations":"Upgrading to a release whose packaging changed layout without an installer update; running on an unusual platform triple whose asset is packaged differently; a release-process regression that nested binaries; proxies/mirrors serving a generic source tarball instead of the binary asset.","solutions":["Inspect the actual layout: extract the release archive for your platform manually (`tar -tf <asset>`) and see where the binary sits.","Pin a known-good version until the layout mismatch is fixed: install with the previously working version number.","Verify the detected platform triple (OS/arch) matches the asset you'd expect — wrong triple can select a differently-laid-out archive.","If the release asset is simply wrong (nested/empty), report it — there is no flag to relocate the binary; the archive must contain it at the root."],"exampleFix":"# before: release asset nests the binary\n$ tar -tf meta-proxy-v9-x86_64-apple-darwin.tar.gz\nmeta-proxy-9.0.0/bin/meta-proxy      # NOT at root -> error 299\n\n# after: pin the last correctly-packaged release\nnpx ruflo@latest proxy install --version 0.4.1   # archive has ./meta-proxy at root","handlingStrategy":"validation","validationCode":"import { execFileSync } from 'node:child_process';\n// Verify the release asset actually has the binary at its root BEFORE installing:\nfunction archiveHasRootBinary(archivePath: string, binary: string): boolean {\n  const listing = execFileSync('tar', ['-tf', archivePath], { encoding: 'utf-8', timeout: 60_000 });\n  return listing.split('\\n').map(l => l.trim().replace(/^\\.\\//, '')).includes(binary);\n}\nif (!archiveHasRootBinary(assetPath, process.platform === 'win32' ? 'meta-proxy.exe' : 'meta-proxy')) {\n  throw new Error(`release asset layout invalid for ${version} — pin a known-good version`);\n}","typeGuard":"function isMissingBinaryError(e: unknown): e is Error {\n  return e instanceof Error && e.message.startsWith('archive did not contain the expected binary at its root');\n}","tryCatchPattern":"try {\n  return await installProxyBinary({ version: 'latest' });\n} catch (e) {\n  if (isMissingBinaryError(e)) {\n    return installProxyBinary({ version: LAST_KNOWN_GOOD_VERSION }); // pin back to a correctly-packaged release\n  }\n  throw e;\n}","preventionTips":["Pin proxy install to a specific known-good version in automation instead of floating latest.","When a new release ships, verify its archive layout (`tar -tf`) for your platform before rolling it out.","Confirm the platform triple detection (os/arch) matches your host so the expected asset layout matches the binary name."],"tags":["proxy","install","archive","binary","packaging"],"backgroundTag":"missing-expected-file","analyzedSha":"29f048fc3b556f857cf2b126d2a84c19d2daa0d0","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}