Understanding UnknownHostException in Android (and Why the API 'Worked Locally')

TIL that an Android UnknownHostException on a hostname that resolved fine everywhere else usually isn't a DNS problem at all — it's the app pointed at a hostname that only ever existed on my dev machine.

2 min read

Sabin Shrestha

Full-Stack Developer — Next.js, React & React Native

The Problem #

The app worked perfectly against the API in development and threw java.net.UnknownHostException on the exact same code path once built and run outside my machine. No amount of restarting the Metro bundler or clearing the cache changed anything, because the bug wasn't in the JavaScript at all.

Context #

Local development used http://localhost:5000 as the API base URL, which resolves fine on the machine running both the app and the API — for a browser or an iOS simulator sharing that machine's network stack.

What I Tried #

Checked the API server itself was up and reachable, confirmed it in a browser on the same machine, and assumed the issue was somewhere in the request code.

What Went Wrong #

I was debugging the wrong layer. The request code was fine — the hostname it was pointed at simply didn't mean what I assumed it meant on an Android device or emulator.

The Solution #

localhost on an Android emulator refers to the emulator's own virtual device, not the host machine running it — the host is reachable at 10.0.2.2 instead. On a physical device, neither works; it needs the host machine's actual LAN IP, or (for anything beyond local testing) a real hostname pointing at deployed infrastructure.

const API_URL = __DEV__
  ? Platform.select({
      android: "http://10.0.2.2:5000", // Android emulator → host machine
      ios: "http://localhost:5000",     // iOS simulator shares the host's network
      default: "http://192.168.1.42:5000", // physical device on the same LAN
    })
  : "https://api.production-domain.com";

Why It Works #

UnknownHostException means exactly what it says: the device genuinely could not resolve that hostname to anything, because localhost on an Android emulator is a real, different, un-configured host — not an alias for "the computer I'm developing on."

Lessons Learned #

An error message that looks like a DNS/networking failure can actually be a configuration assumption baked into a URL constant. The fix wasn't network debugging — it was noticing "localhost" means something different depending on which device is asking.

What I Would Do Differently #

I'd set up platform-aware API base URLs from the very first API call in the project, instead of hardcoding localhost and discovering the platform difference the first time someone tested on Android.

Android emulator networking (10.0.2.2), Platform.select(), dev vs. production API base URLs.