Android ARM64 (Termux): launcher resolves linux-arm64 binary but npm rejects optional dependency (EBADPLATFORM)

Open 💬 1 comment Opened Aug 6, 2026 by cowebsLB

What version of Codex CLI is running?

0.146.1

What subscription do you have?

ChatGPT Plus

Which model were you using?

N/A (CLI does not start)

What platform is your computer?

Android arm64 $ uname -mprs aarch64 aarch64 Android

What terminal emulator and version are you using (if applicable)?

Termux Node.js 26.3.1 npm 12.0.2

Codex doctor report

Not available.

The CLI exits before it can execute any commands due to a missing optional dependency.

What issue are you seeing?

Installing Codex succeeds:

npm install -g @openai/codex@latest

However, running:

codex

fails with:

Error: Missing optional dependency @openai/codex-linux-arm64.
Reinstall Codex: npm install -g @openai/codex@latest

I investigated further.

Node reports:

node -p "process.platform"
android
node -p "process.arch"
arm64

The launcher contains an explicit Android platform case:

case "android":

and maps Android to the target triple:

aarch64-unknown-linux-musl

which resolves to the package:

@openai/codex-linux-arm64

However, that optional dependency is never installed.

What steps can reproduce the bug?

  1. Install Termux on Android (arm64).
  2. Install Node.js and npm.
  3. Run:
npm install -g @openai/codex@latest
  1. Execute:
codex

The CLI exits immediately with:

Missing optional dependency @openai/codex-linux-arm64

Further investigation shows:

npm install -g npm:@openai/codex@0.146.1-linux-arm64

fails with:

EBADPLATFORM

wanted:
os: linux
cpu: arm64

current:
os: android
cpu: arm64

What is the expected behavior?

Either:

  1. Android/Termux is supported, in which case the required platform package should be installable and the CLI should launch successfully.

or

  1. Android/Termux is intentionally unsupported, in which case the installer or launcher should provide a clear "unsupported platform" message instead of reporting a missing optional dependency.

Additional information

The launcher appears to recognize Android:

case "android":

and maps it to the Linux ARM64 target.

However, npm refuses to install the corresponding optional dependency because it is published with:

os: linux
cpu: arm64

while Node on Termux reports:

process.platform = "android"
process.arch = "arm64"

This appears to create a mismatch where the launcher expects the Linux ARM64 package but npm never installs it due to platform metadata.

I'm not certain whether Android/Termux is intended to be supported, but the current behavior seems inconsistent because the launcher explicitly handles the Android platform while the dependency metadata prevents the required binary from being installed.

View original on GitHub ↗

1 Comment

victor-gurbani · 12 days ago

Adding full root cause analysis and a working solution for anyone trying to run the CLI on Android / Termux.

Beyond the initial EBADPLATFORM issue during npm install, there are two subsequent runtime failures when executing the aarch64-unknown-linux-musl binary on Android:

---

1. Root Causes on Android / Termux

  1. Package metadata (EBADPLATFORM):

bin/codex.js already explicitly handles process.platform === "android" and maps it to aarch64-unknown-linux-musl, but the @openai/codex-linux-arm64 npm package only lists "os": ["linux"], causing npm to skip/reject installing the optional binary dependency on Termux where process.platform === "android".

  1. DNS Name Resolution Failure (failed to lookup address information: Try again / EAI_AGAIN):

Musl libc's resolver strictly expects DNS nameservers at /etc/resolv.conf. On Android, /etc/resolv.conf does not exist (Termux stores it at $PREFIX/etc/resolv.conf). This causes all domain lookups (chatgpt.com) to fail.

  1. TLS Certificate Trust Failure (invalid peer certificate: UnknownIssuer):

rustls attempts to load root CA certificates from standard Linux paths (/etc/ssl/certs/ca-certificates.crt, /etc/ssl/cert.pem, /etc/pki/tls/certs/ca-bundle.crt). These paths do not exist in Android's userland (Termux stores the CA bundle at $PREFIX/etc/tls/cert.pem).

---

2. Working Fix in bin/codex.js

We can make the global npm package work out-of-the-box on Termux by updating the launcher wrapper in bin/codex.js:

  1. Exporting SSL_CERT_FILE, SSL_CERT_DIR, and CARGO_HTTP_CAINFO pointing to $PREFIX/etc/tls/cert.pem.
  2. Automatically wrapping execution with proot to bind $PREFIX/etc/resolv.conf and $PREFIX/etc/tls/cert.pem into standard Linux locations when /etc/resolv.conf is missing:
const prefix = process.env.PREFIX || "/data/data/com.termux/files/usr";
const termuxResolv = path.join(prefix, "etc/resolv.conf");
const termuxCert = path.join(prefix, "etc/tls/cert.pem");
let execPath = binaryPath;
let execArgs = process.argv.slice(2);

env.SSL_CERT_FILE = env.SSL_CERT_FILE || termuxCert;
env.SSL_CERT_DIR = env.SSL_CERT_DIR || path.join(prefix, "etc/tls");
env.CARGO_HTTP_CAINFO = env.CARGO_HTTP_CAINFO || termuxCert;
env.LANG = env.LANG || "en_US.UTF-8";
env.LC_ALL = env.LC_ALL || "en_US.UTF-8";
env.LC_CTYPE = env.LC_CTYPE || "en_US.UTF-8";

if (!existsSync("/etc/resolv.conf") && existsSync(termuxResolv)) {
  const prootPath = path.join(prefix, "bin/proot");
  if (existsSync(prootPath)) {
    execPath = prootPath;
    const binds = [
      "-b", `${termuxResolv}:/etc/resolv.conf`,
      "-b", `${termuxCert}:/etc/ssl/cert.pem`,
      "-b", `${termuxCert}:/etc/ssl/certs/ca-certificates.crt`,
      "-b", `${termuxCert}:/etc/pki/tls/certs/ca-bundle.crt`,
    ];
    execArgs = [...binds, binaryPath, ...execArgs];
  }
}

const child = spawn(execPath, execArgs, {
  stdio: "inherit",
  env,
});

---

3. Verification (codex doctor)

With this wrapper in place:

  • WebSocket: Handshake succeeds (HTTP 101 Switching Protocols) to wss://chatgpt.com/backend-api/...
  • Reachability: HTTP provider endpoints pass
  • TUI & Interactive Sessions: Fully functional