karatelabs/karate · error · RuntimeException

proceed() needs a target URL or Host header in request

Error message

proceed() needs a target URL or Host header in request

What it means

When karate.proceed() is called without an explicit target URL, Karate falls back to building the target from the incoming request's Host header ("http://" + host). This error is thrown when there is no argument AND the intercepted request carries no Host header, so Karate has no way to determine where to forward the request.

Solutions

  1. Pass the target URL explicitly: var response = karate.proceed('http://backend:8080')
  2. Ensure the client sends a standard Host header with its request to the mock
  3. If a proxy strips Host, configure it to preserve Host, or use an X-Forwarded-Host value by passing that URL explicitly to proceed()
  4. For test clients, force HTTP/1.1 so Host is mandatory, e.g. curl --http1.1

Example fix

// before
* def response = karate.proceed() // fails if request has no Host header

// after
* def response = karate.proceed('http://backend:8080')
Defensive patterns

Strategy: validation

Validate before calling

// Before relying on Host-header fallback in a mock scenario, pass the URL explicitly when unsure:
var target = 'http://backend:8080';
var response = karate.proceed(target);

Try / catch

try {
  var response = karate.proceed(); // Host-header mode
} catch (e) {
  if (('' + e).indexOf('needs a target URL or Host header') !== -1) {
    var response = karate.proceed('http://backend:8080');
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling karate.proceed() with no arguments from a mock scenario whose incoming request lacks a Host header — e.g. an HTTP/1.0-style client, a raw socket request built without Host, or a request whose Host header was stripped/renamed before reaching the mock.

Common situations: Testing with a minimal HTTP client or curl variant that omits Host; a proxy/load balancer in front of the mock rewriting or dropping the Host header; forwarding non-HTTP-protocol traffic at the mock; passing a custom header name (e.g. X-Forwarded-Host) and expecting proceed() to use it.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/core/KarateJs.java:1008

     * // Forward using Host header from request
     * var response = karate.proceed();
     * </pre>
     */
    private JavaInvokable proceed() {
        return args -> {
            if (mockHandler == null) {
                throw new RuntimeException("proceed() can only be called within a mock scenario");
            }
            HttpRequest currentRequest = mockHandler.getCurrentRequest();

            String targetUrl;
            if (args.length > 0 && args[0] != null) {
                targetUrl = args[0].toString();
            } else {
                // Use Host header from request
                String host = currentRequest.getHeader("Host");
                if (host == null) {
                    throw new RuntimeException("proceed() needs a target URL or Host header in request");
                }
                targetUrl = "http://" + host;
            }

            // Build request manually to avoid header conflicts
            HttpRequestBuilder builder = new HttpRequestBuilder(client);
            builder.url(targetUrl);
            builder.path(currentRequest.getPath());
            builder.method(currentRequest.getMethod());

            // Copy headers except those that will be auto-set
            if (currentRequest.getHeaders() != null) {
                currentRequest.getHeaders().forEach((name, values) -> {
                    String lowerName = name.toLowerCase();
                    // Skip headers that are auto-managed
                    if (!lowerName.equals("content-length") && !lowerName.equals("host")
                            && !lowerName.equals("transfer-encoding")) {
                        builder.header(name, values);

View on GitHub (pinned to a22eb90246)