{"record":{"id":"6fcb59ec4a7bf163","repo":"facebook/flow","slug":"hash-of-flowbinpath-does-not-match-hash-from-sh","errorCode":null,"errorMessage":"Hash of ${flowBinPath} does not match hash from SHASUM256.txt:\nHash of flow binary: ${flowBinHash}\nHash from SHASUM256.txt: ${shasum}","messagePattern":"Hash of (.+?) does not match hash from SHASUM256\\.txt:\nHash of flow binary: (.+?)\nHash from SHASUM256\\.txt: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/flow-for-vscode/src/utils/getVerifiedFlowBinPath.ts","lineNumber":131,"sourceCode":"    // successfully verified SHASUM256.txt, now we can use it to verify the flow binary\n    const { flowBinDirName, flowBinName } =\n      await getFlowBinRelativePath(flowBinModulePath);\n    const flowBinPath = path.join(\n      flowBinModulePath,\n      flowBinDirName,\n      flowBinName,\n    );\n    const hash = createHash('sha256');\n    const flowBinReadStream = createReadStream(flowBinPath);\n    const flowBinHashPromise = new Promise((resolve, reject) => {\n      flowBinReadStream.on('end', () => resolve(hash.digest('hex')));\n      flowBinReadStream.on('error', reject);\n    });\n    flowBinReadStream.pipe(hash);\n    const flowBinHash = await flowBinHashPromise;\n    const shasum = getShasum(shasums.toString(), flowBinDirName, flowBinName);\n    if (flowBinHash !== shasum) {\n      throw new Error(\n        `Hash of ${flowBinPath} does not match hash from SHASUM256.txt:\\n` +\n          `Hash of flow binary: ${flowBinHash}\\n` +\n          `Hash from SHASUM256.txt: ${shasum}`,\n      );\n    }\n    return flowBinPath;\n  } catch (err: any) {\n    logger.error(\n      `Error when verifying flow-bin in ${flowBinModulePath}:\\n${err.message}`,\n    );\n    // failed to verify SHASUM256.txt; ask the user whether to proceed anyway\n    const quickPickOptions = {\n      title: `Unable to verify the integrity of ${flowBinModulePath}. Proceed anyway?`,\n    };\n    const quickPickItems = [\n      {\n        label: `Don't try to use ${flowBinModulePath}`,\n        proceedAnyway: false,","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/facebook/flow/blob/d1341dac899a79c027762f6b423d896045287620/packages/flow-for-vscode/src/utils/getVerifiedFlowBinPath.ts#L113-L149","documentation":"The final verification step streams the flow binary through sha256 and compares the digest against the SHASUM256.txt entry. A mismatch throws with both hashes. The outer getVerifiedFlowBinPath catches it, logs it, and shows a QuickPick asking whether to proceed — a corrupted or tampered binary is never used silently.","triggerScenarios":"The binary on disk does not match its published checksum: truncated or corrupted download, post-install patching (ad-hoc codesign on macOS, patchelf/ELF rewriting), or genuine tampering.","commonSituations":"Flaky network corrupting the npm download; macOS gatekeeper/codesign modifications; packagers (nix, patchelf) rewriting binaries; supply-chain tampering — the case this guard exists for.","solutions":["Stop at the prompt and reinstall flow-bin: `npm ci`, or remove node_modules/flow-bin and reinstall","If you intentionally patch the binary (codesign/patchelf), accept the prompt knowingly, or bypass verification by setting pathToFlow to an externally managed binary","Compare the two hashes in the message; report persistent mismatches to the flow repo and never blindly click 'proceed' on shared machines"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import {createHash} from 'crypto';\nimport {createReadStream} from 'fs';\n\nasync function fileMatchesSha256(\n  filePath: string,\n  expected: string,\n): Promise<boolean> {\n  return new Promise((resolve) => {\n    const hash = createHash('sha256');\n    const stream = createReadStream(filePath);\n    stream.on('end', () => resolve(hash.digest('hex') === expected));\n    stream.on('error', () => resolve(false));\n    stream.pipe(hash);\n  });\n}","typeGuard":null,"tryCatchPattern":"// getVerifiedFlowBinPath already catches this and asks the user via\n// QuickPick; if you call it yourself, mirror that policy — never proceed\n// silently:\ntry {\n  const p = await getVerifiedFlowBinPath(flowBinModulePath, logger);\n} catch (err) {\n  if (/does not match hash from SHASUM256.txt/.test(err.message)) {\n    // stop, notify security/owner, reinstall flow-bin\n  } else throw err;\n}","preventionTips":["Use npm ci in CI so flow-bin is fetched deterministically","Never bypass the proceed-anyway prompt without recording why","If you patch binaries (codesign/patchelf), manage verification yourself via pathToFlow","Treat a mismatch on shared machines as a possible supply-chain incident"],"tags":["flow-bin","checksum","sha256","tampering","security"],"backgroundTag":"checksum-mismatch","analyzedSha":"d1341dac899a79c027762f6b423d896045287620","analyzedAt":"2026-08-17T00:07:02.212Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}