You install a CLI with npm. The install finishes with no errors. Then you run the command and Windows answers with a dialog about a 16-bit application...... which is a strange thing to hear on a 64-bit machine in 2026.
I ran into this on my own box and spent way too long blaming the wrong things. Here's what's actually going on, and the fix that worked in my case.
The three error strings
One failure, three outfits:
- From Explorer, a double-click: the "Unsupported 16-Bit Application" dialog
- From PowerShell:
Program 'opencode.exe' failed to run: The specified executable is not a valid application for this OS platform - From cmd:
This version of ... is not compatible with the version of Windows you're running
I reproduced both console messages directly on Windows 11. The Explorer dialog wording comes from the bug reporter's screenshot, so treat that one as reported rather than something I generated myself.
Why Windows starts talking about 16-bit
Because the file you're running isn't a program.
Real Windows executables start with the bytes 4D 5A (MZ) followed by a PE header. CreateProcess checks for that, and when it's missing you get whichever legacy message the OS has lying around. On newer Windows builds, that lookup is what produces the 16-bit wording.
I unpacked the published tarball to check. opencode-ai@1.18.30's bin/opencode.exe is 479 bytes of plain ASCII shell script. First two bytes are 65 63, which is just the word echo. The real Windows binary lives in a separate platform package (opencode-windows-x64, around 179 MB) and a postinstall script copies it over the stub at install time.
Claude Code pulls the same trick. Its stub is 500 bytes of text and prints:
Error: claude native binary not installed.
Either postinstall did not run (--ignore-scripts, some pnpm configs)
or the platform-native optional dep is missing
A refreshingly blunt error message. The catch is you only see it if you open the file instead of trying to run it.
Why the install step never happened
-
ignore-scripts=truein your npm config. npm runs thepreinstall,installandpostinstalllifecycle scripts for a package. Turn scripts off globally and nothing ever replaces the stub. - npm 12's install-script allowlist. Newer npm versions can restrict install scripts to an approved list, which is a reasonable supply chain control. Your install log says something like
warn install-scripts ... blocked because they are not covered by allowScripts. If you're on npm 10 like me you won't see this at all. -
omit=optionalin your config. Most of these tools declare the platform binary as an optional dependency, so omitting optional deps means the helper never lands. I tested it with esbuild:--omit=optionaldrops@esbuild/win32-x64cleanly and quietly. - Or the publisher dropped the ball. Claude Code 2.1.237 shipped the main package while
@anthropic-ai/claude-code-win32-x64@2.1.237returned 404, so the optional dep got skipped and the 500-byte stub stayed. The missing package showed up on the registry about an hour later, which doesn't help you while you're staring at a broken command.
Diagnose it in about 30 seconds
npm config get ignore-scripts
npm config get omit
npm ls -g --depth=0
Then look at the file without running it:
$cli = "$(npm root -g)\opencode-ai\bin\opencode.exe"
(Get-Item $cli).Length # 479 = stub, hundreds of MB = the real thing
Get-Content $cli -TotalCount 3 # ASCII text = stub
A real binary here is hundreds of megabytes. 479 bytes is a signpost, not a program. If you want to be certain, Format-Hex -Path $cli -Offset 0 -Count 2 should show 4D 5A.
The fix, in order
If scripts are blocked, re-run the install step for the package already on disk:
npm rebuild -g opencode-ai
That runs the lifecycle scripts again. In my case it took the stub from 479 bytes to 179,793,448 bytes and opencode --version answered on the next try. No reinstall, no reboot.
Same thing, said explicitly:
node "$(npm root -g)/opencode-ai/postinstall.mjs"
If npm 12's allowlist is the blocker:
npm i -g opencode-ai@latest --allow-scripts=opencode-ai
Worth knowing before you read the wrong forum post: --foreground-scripts does not bypass the allowlist. It only streams script output to your terminal, so it looks like it did nothing.
If the optional dependency was omitted:
npm i -g opencode-ai@latest --include=optional
If the publisher's platform package is missing, pin the last good build. Check first:
npm view @anthropic-ai/claude-code-win32-x64 versions
npm i -g @anthropic-ai/claude-code@2.1.236
And if the global tree is half-written, usually after the CLI's own self-update died partway (cline users know this one), do a clean reinstall with npm i -g <pkg>@latest and confirm the shim with where <pkg> afterwards.
Verify
opencode --version
(Get-Item "$(npm root -g)\opencode-ai\bin\opencode.exe").Length
npm ls -g --depth=0
Two things to keep in mind
The 16-bit wording sends people into compatibility mode and 32-vs-64-bit rabbit holes. It's neither. It's a file that isn't an executable.
On a locked-down work machine, install scripts may be disabled by policy, in which case npm rebuild can be blocked too. Manual postinstall runs do nothing at all if the platform package isn't installed, so read the output instead of assuming it worked.
The platform-binary pattern is standard now. esbuild, sharp, rollup, playwright and most AI coding CLIs use it. Once you accept that the command you're running might be a placeholder, these errors stop being mysterious. Hope this saves you the hour I lost.
Top comments (0)