DEV Community

Cover image for Illegal Instruction: How I Woke Up a Year-Old 'Not Planned' Bug and (Almost) Fixed Vite on Android
Gouranga Das Samrat
Gouranga Das Samrat

Posted on

Illegal Instruction: How I Woke Up a Year-Old 'Not Planned' Bug and (Almost) Fixed Vite on Android

My dev server didn't start. It just died.

$ pnpm create vite test-react-app --template react-compiler-ts
$ cd test-react-app && pnpm run dev
Illegal instruction        pnpm run dev
Enter fullscreen mode Exit fullscreen mode

No stack trace a human can read. No hint about what to fix. Just Illegal instruction, and the terminal handing control back like nothing happened. Same story for create-vue. Same story for a plain vite dev. Three different starter templates, one identical crash.

This was on a Termux install on an Android tablet, not some exotic setup. And that detail matters more than it sounds like it should, because a lot of people's only computer is the phone in their pocket. I'm one of them some days. If you're learning to code from Bangladesh, Nigeria, Indonesia, or a dozen other places, a laptop isn't a given — Termux on an old Android phone is often the whole dev environment. When the standard npm create vite path doesn't work there, it's not a minor inconvenience. It's a wall.

Chasing the actual cause

I started where anyone would: assume it's a Termux problem. Filed termux/termux-packages#30841 with logs for Next.js, Vite+React, and Vue, all crashing or silently falling back to a slower path.

Termux maintainer robertkirkman pointed out that pkg install turbopack fixes the Next.js case, since Turbopack is packaged for Termux directly. Tried it — true, but only for Next.js. Vite and Vue don't touch Turbopack at all, and they were still crashing exactly the same way.

That's when it became clear this wasn't a packaging gap. Vite 6 and up ships Rolldown as its default bundler, a Rust-based, N-API bundler that loads a native binary — @rolldown/binding-android-arm64 for our case. Something in that binary was blowing up the moment it loaded.

truboxl, another Termux maintainer, asked for a logcat tombstone instead of just terminal output, and that's where the real evidence showed up:

pid: 32487, tid: 32487, name: MainThread  >>> node <<<
ABI: 'arm64'
signal 4 (SIGILL), code 1 (ILL_ILLOPC), fault addr 0x6eb3132d64 (*pc=0xc8e9fe93)

backtrace:
  #00 pc 00000000006e2d64  .../rolldown-binding.android-arm64.node
  #01 pc 00000000006e2474  .../rolldown-binding.android-arm64.node
  #02 pc 000000000004a1d8  linker64 (call_array+288)
  #03 pc 000000000004a3d4  linker64 (soinfo::call_constructors+380)
  #04 pc 0000000000035a9c  linker64 (do_dlopen+2076)
Enter fullscreen mode Exit fullscreen mode

That's a crash happening during dlopen, inside the native .node binary itself, before a single line of JS runs. The classic fingerprint of a native binary compiled with instruction-set assumptions that don't hold on the chip actually running it. Not a Termux bug at all. truboxl confirmed it and labeled it an upstream issue.

The ghost in the closet

Naturally, the next move was to go report this to Rolldown. Except somebody already had.

Buried in the Rolldown repo was rolldown/rolldown#6342 — "Illegal instruction on android arm64" — opened back in September 2025 by a user named hyperz111. Same crash signature, same platform. He'd shared a screen recording and full CPU info because he couldn't put together a minimal reproduction repo. The auto-reply bot wanted a reproduction within 14 days or the issue would close. Nobody circled back in time, and it closed as not planned in October 2025.

Ten months of silence followed. Nearly a year of Vite quietly not working on Android, and basically nobody talking about it.

Here's the part that bugged me most: "not planned" reads like a policy decision — we've decided Android isn't a target we support. But that's not actually what was true. Rolldown was already building and publishing @rolldown/binding-android-arm64 on every release. The platform wasn't unsupported in theory; it was broken in practice, and a bot closed the thread because a repro checkbox never got ticked. A build bug got mistaken for a feature request nobody asked for, and then everyone — including me, at first — treated "closed as not planned" as a dead end instead of what it actually was: an unfinished conversation.

In the meantime, I filed termux/termux-packages#30852 asking Termux to package Rolldown directly, the same way it already packages Turbopack, since going through upstream looked like it was going nowhere.

Going back with receipts

But a package request downstream doesn't fix the actual bug upstream. So robertkirkman went back to the closed Rolldown issue with the tombstone trace in hand and reframed the ask. This wasn't "please make Android a fully maintained target." It was narrower: the android-arm64 build already exists and already ships, it's crashing at load on real silicon, and that's a cross-compilation flag problem, not a support-commitment problem.

That reframing is what actually moved it. Rolldown maintainer shulaoda reopened #6342 and was refreshingly honest about the gap: the team doesn't have a shelf of random Android devices to test against, so verification from someone with the actual crashing hardware was exactly what they needed.

Then sapphi-red spotted the likely root cause, and it's a satisfying one: Rolldown depends on mimalloc, and its no_opt_arch feature — the thing that stops mimalloc from assuming newer ARM instructions are present — was only being enabled when target_os = "linux". Android runs on Linux under the hood but reports a different target_os, so the Android build skipped that safety flag entirely and got compiled assuming ARMv8.1 atomic instructions that a chip like a Cortex-A53 simply doesn't have. Since mimalloc initializes inside a library constructor, that lines up exactly with a SIGILL at dlopen, before any of Rolldown's own code even runs.

shulaoda shipped a preview build in rolldown/rolldown#10638 within the same day and asked for someone with the affected hardware to verify it.

Testing it on the actual crashing device

So I did. Cortex-A53, MediaTek MT6762V, the same tablet that had been throwing Illegal instruction this whole time.

$ npx rolldown@1.2.3 --version
Illegal instruction

$ pnpm i https://pkg.pr.new/rolldown@10638
$ npx rolldown --version
rolldown v1.2.3+commit.a7ba7ad
Enter fullscreen mode Exit fullscreen mode

No crash. Then the real test: a fresh Vite + React project.

$ pnpm create vite test-react-app --template react-compiler-ts
$ pnpm run dev
  VITE v6.x.x  ready in 412 ms
  ➜  Local:   http://localhost:5173/
Enter fullscreen mode Exit fullscreen mode

It just worked. Ten months of Illegal instruction, gone with one removed target_os condition.

Then I tweeted it

I posted the whole trail on X, tagging Evan You, the Rolldown team, and Vite. Rolldown's shulaoda — Jerry Zhao — replied publicly the next day, confirmed the team was taking it seriously, and pointed back at the reopened issue and the preview build. I replied that I was already testing it on the affected device and would post results on the issue. Small exchange, but it's the kind of public back-and-forth that keeps an issue from quietly dying a second time.

The side quest nobody asked for

While all this was happening upstream, the Termux side didn't just sit around waiting for a release. Contributor DevGitPit opened termux/termux-packages#30887 to package Rolldown 1.2.3 downstream anyway, so Termux users wouldn't be stuck waiting on Rolldown's release cycle. That PR turned into its own small collaboration — robertkirkman debugging build errors alongside DevGitPit, and at one point asking the Rolldown team directly whether they'd consider supporting more Android ABIs (32-bit ARM, x86, x86_64) beyond just arm64, since some Termux users are on hardware Rolldown doesn't build for at all.

Two separate open-source projects, two separate maintainer teams, ended up helping each other out over the same crash. Termux gave Rolldown a real device to test against and a trace nobody on the Rolldown side could have reproduced. Rolldown gave Termux users a real fix instead of a permanent downstream patch to maintain forever.

Where it stands right now

The fix works. I've confirmed it on the exact hardware that was crashing. It hasn't landed in a release yet — the preview build is verified, the PR is open, and it's waiting on the Rolldown team to merge and cut a new version. Once that happens, npm install -g rolldown (or just running create vite) should work on Android arm64 without anyone needing a Termux-specific package at all.

Why I bothered writing this up

"Closed as not planned" isn't always a wall. Sometimes it's a bot doing its job on an issue that never got the follow-up it needed. The difference between a bug staying closed for another year and getting fixed in a week wasn't cleverness — it was a device to reproduce it on, a tombstone instead of a vague description, and enough persistence to go back and ask for the closed issue to be looked at differently instead of filing yet another duplicate.

If you're running Termux on Android arm64 and hit this, or you're on different silicon — an older Snapdragon, an Exynos, anything that isn't a Cortex-A53 — go pull the fix from #10638 and drop a comment on #6342 with what you find. More devices means more confidence before it ships, and right now that's the only thing standing between this bug and actually being closed for good.

Top comments (0)