java.net.UnknownHostException: Causes and Fixes
java.net.UnknownHostException is thrown when the JVM cannot resolve a hostname to an IP address. The fix is almost always in DNS configuration, the URL itself, or the network layer β rarely in the Java code.
When does it happen?
Anywhere the JDK performs a DNS lookup:
new URL("https://example.com").openConnection()InetAddress.getByName("example.com")HttpClient.send(...)- JDBC, JMS, Kafka, or any networked driver on its first connection
Typical message:
Exception in thread "main" java.net.UnknownHostException: example.internal
at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:567)
at java.base/java.net.Socket.connect(Socket.java:633)
Cause 1 β Typo in the hostname
By far the most common. http://localhot instead of localhost, my-server instead of my-server.internal.corp. Check the hostname with a plain command-line tool first:
nslookup example.com
dig example.com
ping example.com
If the OS cannot resolve the name, Java won't either.
Cause 2 β No internet / VPN disconnected
Internal hostnames (like jira.internal.company.com) often require a VPN. Disconnected laptops hit this daily. Reconnect the VPN and retry.
Cause 3 β Proxy required but not configured
Corporate networks often force traffic through a proxy. Tell the JVM:
java \
-Dhttp.proxyHost=proxy.corp \
-Dhttp.proxyPort=8080 \
-Dhttps.proxyHost=proxy.corp \
-Dhttps.proxyPort=8080 \
-Dhttp.nonProxyHosts="localhost|*.internal" \
-jar app.jar
Cause 4 β /etc/hosts missing an entry
On Linux/macOS, local overrides live in /etc/hosts. On Windows, C:\Windows\System32\drivers\etc\hosts. A custom name like api.mylocal needs an entry:
127.0.0.1 api.mylocal
Cause 5 β JVM DNS cache poisoning
Java caches DNS lookups in the JVM. If a host was briefly unreachable and then came back, the cached failure may persist for the lifetime of the process. Tune the cache TTL:
java -Dsun.net.inetaddr.ttl=60 -Dsun.net.inetaddr.negative.ttl=10 -jar app.jar
For cloud-native apps where DNS changes frequently (service discovery, rolling deployments), set the positive TTL low (30β60 seconds).
Cause 6 β IPv4 vs IPv6 mismatch
Some networks advertise AAAA (IPv6) records but don't route IPv6 packets. The JVM prefers IPv6 by default, which can cause spurious failures. Force IPv4:
java -Djava.net.preferIPv4Stack=true -jar app.jar
Diagnostic checklist
- Print the exact hostname that failed:
try { ... } catch (UnknownHostException e) { logger.error("DNS resolution failed for: {}", e.getMessage()); } - Resolve it from the OS:
nslookup <hostname>. - If OS works but Java doesn't, check proxy settings and IPv4/IPv6.
- If neither works, the issue is network (VPN, firewall, /etc/hosts).
- Enable JDK DNS debug:
-Djava.net.debug=trueβ verbose but enlightening.
Handling the exception programmatically
For a service that depends on remote APIs, catching it lets you retry gracefully:
public String fetchWithRetry(String url, int maxAttempts) throws IOException, InterruptedException {
IOException last = null;
for (int attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return HttpClient.newHttpClient()
.send(HttpRequest.newBuilder(URI.create(url)).build(),
HttpResponse.BodyHandlers.ofString())
.body();
} catch (UnknownHostException e) {
last = e;
Thread.sleep(Duration.ofSeconds(1L << attempt).toMillis());
}
}
throw last;
}
Exponential backoff gives the DNS layer a chance to recover (VPN reconnect, DNS cache refresh, transient outage).
Fast summary
| Symptom | Likely cause |
|---|---|
| Only fails for internal hosts | VPN or /etc/hosts |
| Fails everywhere | No internet or proxy needed |
| Works then stops | JVM DNS cache |
| Sometimes works, sometimes not | IPv4/IPv6 or DNS round-robin |
| Works with browser but not Java | Proxy system settings vs JVM |
Once you know the category, the fix is usually minutes away.