{"record":{"id":"1ca8cc283419ba57","repo":"apache/hadoop","slug":"localhost-targeted-connection-resulted-in-a-loopba","errorCode":null,"errorMessage":"Localhost targeted connection resulted in a loopback. No daemon is listening on the target port.","messagePattern":"Localhost targeted connection resulted in a loopback\\. No daemon is listening on the target port\\.","errorType":"exception","errorClass":"ConnectException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/NetUtils.java","lineNumber":631,"sourceCode":"        SocketIOWithTimeout.connect(ch, endpoint, timeout);\n      }\n    } catch (SocketTimeoutException ste) {\n      throw new ConnectTimeoutException(ste.getMessage());\n    }  catch (UnresolvedAddressException uae) {\n      throw new UnknownHostException(endpoint.toString());\n    }\n\n    // There is a very rare case allowed by the TCP specification, such that\n    // if we are trying to connect to an endpoint on the local machine,\n    // and we end up choosing an ephemeral port equal to the destination port,\n    // we will actually end up getting connected to ourself (ie any data we\n    // send just comes right back). This is only possible if the target\n    // daemon is down, so we'll treat it like connection refused.\n    if (socket.getLocalPort() == socket.getPort() &&\n        socket.getLocalAddress().equals(socket.getInetAddress())) {\n      LOG.info(\"Detected a loopback TCP socket, disconnecting it\");\n      socket.close();\n      throw new ConnectException(\n        \"Localhost targeted connection resulted in a loopback. \" +\n        \"No daemon is listening on the target port.\");\n    }\n  }\n  \n  /** \n   * Given a string representation of a host, return its ip address\n   * in textual presentation.\n   * \n   * @param name a string representation of a host:\n   *             either a textual representation its IP address or its host name\n   * @return its IP address in the string format\n   */\n  public static String normalizeHostName(String name) {\n    try {\n      return InetAddress.getByName(name).getHostAddress();\n    } catch (UnknownHostException e) {\n      return name;","sourceCodeStart":613,"sourceCodeEnd":649,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/NetUtils.java#L613-L649","documentation":"ConnectException from NetUtils.connect when a connection to a local endpoint 'succeeded' but the local port equals the remote port and the local address equals the remote address — the rare TCP self-connect permitted by the RFC, possible only when the OS hands you an ephemeral source port identical to the (dead) destination port. Hadoop detects the loopback, closes the socket, and reports it as connection refused because the target daemon cannot have been listening. The log line 'Detected a loopback TCP socket, disconnecting it' precedes the throw.","triggerScenarios":"Connecting to localhost:<port> while no daemon listens on <port> and the OS happens to allocate <port> as the ephemeral source port (probability ~1/ephemeral-range per attempt); repeated rapid stop/start of daemons in tests increases the chance.","commonSituations":"Integration tests that kill and restart NameNode/DataNode/ResourceManager in tight loops; a daemon crashing between the client's port check and its connect; flaky CI where the failure appears as 'connection refused' to a port the test just closed.","solutions":["Treat it exactly like connection refused: retry the connection with backoff — the ephemeral collision is transient","Verify the target daemon is actually listening: 'ss -ltnp | grep <port>'","In tests, drain/wait on the port between stop and start, or use SO_REUSEADDR-style hygiene, and shrink the ephemeral window collisions by not reusing the same port instantly"],"exampleFix":"// before\nNetUtils.connect(socket, addr, timeout); // rare: ConnectException \"Localhost targeted connection resulted in a loopback\" -> test flakes\n\n// after\nfor (int i = 0; i < 3; i++) {\n  try { NetUtils.connect(socket, addr, timeout); break; }\n  catch (ConnectException e) { /* loopback self-connect == refused: retry */ sleep(backoff); }\n}","handlingStrategy":"retry","validationCode":"// Cannot be pre-validated deterministically (OS-dependent ephemeral pick),\n// but you can check the daemon is listening first:\n// ss -ltn | grep <port>  (shell-level)","typeGuard":null,"tryCatchPattern":"catch (ConnectException e) { /* loopback self-connect == refused */ wait(backoff); retry connect with a fresh socket; after N attempts, surface 'daemon not listening on <port>'; }","preventionTips":["Retry on ConnectException with backoff — the self-connect case cannot persist","In tests, wait for the port to close before rebinding it","Treat 'Localhost targeted connection resulted in a loopback' as connection refused for alerting purposes"],"tags":["tcp","connect","connection-refused","loopback","hadoop-common"],"backgroundTag":"connection-refused","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}