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

  1. Print the exact hostname that failed:
    try {
        ...
    } catch (UnknownHostException e) {
        logger.error("DNS resolution failed for: {}", e.getMessage());
    }
  2. Resolve it from the OS: nslookup <hostname>.
  3. If OS works but Java doesn't, check proxy settings and IPv4/IPv6.
  4. If neither works, the issue is network (VPN, firewall, /etc/hosts).
  5. 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

SymptomLikely cause
Only fails for internal hostsVPN or /etc/hosts
Fails everywhereNo internet or proxy needed
Works then stopsJVM DNS cache
Sometimes works, sometimes notIPv4/IPv6 or DNS round-robin
Works with browser but not JavaProxy system settings vs JVM

Once you know the category, the fix is usually minutes away.