karatelabs/karate · warning

HTTP not available after attempts

Error message

HTTP {} not available after {} attempts

What it means

`PortUtils.waitForHttp` completed all attempts without receiving a successful (expected) HTTP response from the URL. It logs this warning and returns false, indicating the endpoint never returned 200 within the budget.

Solutions

  1. Verify the health endpoint URL and path return 200 (curl it manually)
  2. Increase `attempts`/`intervalMs` to accommodate warm-up time
  3. Check the app logs for what it returns on the probe path
  4. Ensure downstream dependencies the health check requires are available

Example fix

// before
boolean ok = PortUtils.waitForHttp("http://localhost:8080/status", 10, 250, alive);
// after
boolean ok = PortUtils.waitForHttp("http://localhost:8080/actuator/health", 60, 500, alive);
Defensive patterns

Strategy: retry

Try / catch

if (!PortUtils.waitForHttp(url, 60, 500, alive)) {
    throw new RuntimeException("HTTP " + url + " never returned 200; inspect server logs");
}

Prevention

When it happens

Trigger: `waitForHttp('http://localhost:8080/health', 20, 500, alive)` where the endpoint returns 500/404 or connection fails each time; app slow to start so every probe hits a non-200; wrong health path.

Common situations: Health endpoint path changed or misconfigured; app returning 503 during long warm-up; TLS/proxy issues causing connection errors; readiness depends on downstream services that are also down.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/9395bf326d0e2dea. Report an issue: GitHub.

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/process/PortUtils.java:107

            }
            try {
                HttpRequest request = HttpRequest.newBuilder()
                        .uri(URI.create(url))
                        .timeout(Duration.ofSeconds(5))
                        .GET()
                        .build();
                HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
                if (response.statusCode() >= 200 && response.statusCode() < 300) {
                    logger.debug("HTTP {} is available after {} attempts", url, i + 1);
                    return true;
                }
                logger.trace("HTTP {} returned {} (attempt {})", url, response.statusCode(), i + 1);
            } catch (Exception e) {
                logger.trace("HTTP {} not available (attempt {}): {}", url, i + 1, e.getMessage());
            }
            sleep(intervalMs);
        }
        logger.warn("HTTP {} not available after {} attempts", url, attempts);
        return false;
    }

    /**
     * Find a free port.
     */
    public static int findFreePort() {
        try (ServerSocket socket = new ServerSocket(0)) {
            return socket.getLocalPort();
        } catch (Exception e) {
            throw new RuntimeException("failed to find free port", e);
        }
    }

    private static void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {

View on GitHub (pinned to a22eb90246)