{"record":{"id":"0eaba595f37c9c78","repo":"apache/druid","slug":"unable-to-parse-port-out-of-s","errorCode":null,"errorMessage":"Unable to parse port out of %s","messagePattern":"Unable to parse port out of (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"server/src/main/java/org/apache/druid/rpc/ServiceLocation.java","lineNumber":160,"sourceCode":"  private static String getHostFromString(@NotNull String s)\n  {\n    Iterator<String> iterator = HOST_SPLITTER.split(s).iterator();\n    ImmutableList<String> strings = ImmutableList.copyOf(iterator);\n    return strings.get(0);\n  }\n\n  private static int getPortFromString(String s)\n  {\n    if (s == null) {\n      return -1;\n    }\n    Iterator<String> iterator = HOST_SPLITTER.split(s).iterator();\n    ImmutableList<String> strings = ImmutableList.copyOf(iterator);\n    try {\n      return Integer.parseInt(strings.get(1));\n    }\n    catch (NumberFormatException e) {\n      throw new ISE(e, \"Unable to parse port out of %s\", strings.get(1));\n    }\n  }\n\n  public String getHost()\n  {\n    return host;\n  }\n\n  /**\n   * Returns a host:port string for the preferred port (TLS if available; plaintext otherwise).\n   */\n  public String getHostAndPort()\n  {\n    if (tlsPort > 0) {\n      return host + \":\" + tlsPort;\n    } else {\n      return host + \":\" + plaintextPort;\n    }","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/rpc/ServiceLocation.java#L142-L178","documentation":"ServiceLocation.getPortFromString splits a \"host:port\"-style string and parses the second token as an integer port. When the token after the delimiter is missing or non-numeric, Integer.parseInt throws NumberFormatException and this ISE is raised wrapping it.","triggerScenarios":"Calling plaintextPort or tlsPort on a host string whose second split token is not a number — e.g. \"broker.internal\" (no port) or \"broker.internal:http\".","commonSituations":"Legacy configuration keys that list servers as host:port where the port was dropped or replaced by a hostname alias; IPv6 addresses confusing the splitter; migration from other discovery formats.","solutions":["Ensure the server string includes a numeric port: change \"broker.internal\" to \"broker.internal:8082\".","Validate the port substring with Integer.parseInt yourself before passing the host string in.","Switch to constructing ServiceLocation directly with host and port ints instead of parsing strings."],"exampleFix":"// before\nString server = \"broker.internal\";\nServiceLocation loc = ServiceLocation.fromPlainText(server, tls, basePath);\n// after\nString server = \"broker.internal:8082\";\nServiceLocation loc = ServiceLocation.fromPlainText(server, tls, basePath);","handlingStrategy":"validation","validationCode":"String portPart = server.contains(\":\") ? server.substring(server.lastIndexOf(':') + 1) : null;\nif (portPart == null || !portPart.matches(\"\\\\d+\")) {\n  throw new IllegalArgumentException(\"Server string must be host:numericPort: \" + server);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep server lists in host:port format and validate at config load time.","Avoid hostnames without ports in discovery-related properties."],"tags":["port-parsing","number-format","rpc"],"backgroundTag":"invalid-argument-format","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}