{"record":{"id":"045192dd5c8bc888","repo":"NousResearch/hermes-agent","slug":"stage-native-deps-get-windows-binding-dir-nod","errorCode":null,"errorMessage":"[stage-native-deps] get-windows binding ${dir}/node-get-windows.node: expected ${platform}, got ${classified ?? 'unknown'}. Refusing to stage a binary compiled for the wrong platform.","messagePattern":"\\[stage-native-deps\\] get-windows binding (.+?)/node-get-windows\\.node: expected (.+?), got (.+?)\\. Refusing to stage a binary compiled for the wrong platform\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"apps/desktop/scripts/stage-native-deps.mjs","lineNumber":515,"sourceCode":"      rebuild()\n      bindingDirs = scanBindingDirs()\n    }\n    if (bindingDirs.length === 0) {\n      throw new Error(\n        '[stage-native-deps] get-windows has no win32 prebuilt binding under lib/binding. ' +\n          'Recover from the checkout root with:\\n' +\n          '  npm install-scripts approve get-windows\\n' +\n          '  npm rebuild get-windows'\n      )\n    }\n    for (const dir of bindingDirs) {\n      const dest = join(destRoot, 'lib', 'binding', dir)\n      mkdirSync(dest, { recursive: true })\n      const destFile = join(dest, 'node-get-windows.node')\n      cpSync(join(bindingRoot, dir, 'node-get-windows.node'), destFile)\n      const classified = classifyNativeBinary(destFile)\n      if (classified !== platform) {\n        throw new Error(\n          `[stage-native-deps] get-windows binding ${dir}/node-get-windows.node: ` +\n            `expected ${platform}, got ${classified ?? 'unknown'}. ` +\n            'Refusing to stage a binary compiled for the wrong platform.'\n        )\n      }\n    }\n  }\n\n  console.log(`[stage-native-deps] staged get-windows (${platform}) -> ${destRoot}`)\n  return destRoot\n}\n\nfunction rebuildGetWindowsViaNpm() {\n  const result = spawnSync('npm', ['rebuild', 'get-windows'], {\n    cwd: resolve(projectRoot, '..', '..'),\n    stdio: 'inherit',\n    // npm resolves to npm.cmd on Windows, which needs a shell.\n    shell: process.platform === 'win32'","sourceCodeStart":497,"sourceCodeEnd":533,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/apps/desktop/scripts/stage-native-deps.mjs#L497-L533","documentation":"Thrown by the desktop app's native-dependency staging build script (apps/desktop/scripts/stage-native-deps.mjs) after copying a prebuilt get-windows N-API binding into the staged output. The script classifies the staged .node binary's target platform (via classifyNativeBinary, which inspects PE/Mach-O/ELF headers) and compares it to the platform it is staging for. A mismatch means the node_modules cache or checkout contains a binding compiled for a different OS/arch than the current build target, and staging a wrong-platform binary would produce a runtime 'Invalid ELF class'/'%1 is not a valid Win32 application'-style crash later.","triggerScenarios":"Running the stage script (or a desktop build that invokes it) when join(bindingRoot, dir, 'node-get-windows.node') is a binary for another platform/arch than the `platform` argument — e.g. switching between linux and win32 CI runners without a clean npm rebuild, restoring node_modules from a cache built on another OS, or cross-compiling with an env (npm_config_platform / --os) that disagrees with the prebuilt binaries present.","commonSituations":"CI cache poisoning (node_modules cached per-branch but shared across runner OSes), checking out on Windows after building on Linux (or vice versa), using a package cache/mirror that served the wrong prebuild, or running under Rosetta/emulation where arch (x64 vs arm64) detection diverges from the staged binaries.","solutions":["Delete node_modules and the get-windows prebuild cache, then reinstall: `rm -rf node_modules && npm install` so bindings are fetched/built for the current platform.","If the prebuilt binary came from a `npm rebuild get-windows` on another OS, run the recovery printed just above the throw: `npm install-scripts approve get-windows && npm rebuild get-windows` from the checkout root.","Verify npm_config_platform/os/arch env vars or .npmrc overrides are not forcing a cross-platform install; unset them and reinstall.","On CI, key the node_modules cache on runner OS+arch so a linux-built cache never lands on a win32 runner."],"exampleFix":"# before (stale cross-platform node_modules)\nnpm run build:desktop   # -> [stage-native-deps] get-windows binding ... expected win32, got linux\n\n# after\ngit clean -fdx apps/desktop\nrm -rf node_modules node_modules/get-windows\nnpm install-scripts approve get-windows\nnpm rebuild get-windows\nnpm run build:desktop","handlingStrategy":"validation","validationCode":"// Before staging, classify every binding and fail fast with a clear message\nimport { classifyNativeBinary } from './stage-native-deps.mjs'\nfor (const dir of bindingDirs) {\n  const got = classifyNativeBinary(join(bindingRoot, dir, 'node-get-windows.node'))\n  if (got !== process.platform) {\n    console.error(`Skipping stage: ${dir} binding is ${got}, expected ${process.platform}. Run: npm rebuild get-windows`)\n    process.exit(1)\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Key node_modules caches on OS+arch in CI so cross-platform caches never mix","Run `npm rebuild get-windows` after switching runner OS or arch","Treat this throw as a hard build failure — never bypass the platform check to 'get the build green'"],"tags":["build","native-modules","desktop","cross-platform","node-abi"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}