karatelabs/karate · error · RuntimeException
incomplete http request, 'url' not set
Error message
incomplete http request, 'url' not set
What it means
HttpRequestBuilder.buildInternal() validates that a target URL was configured before assembling the request. If url is still null — nothing called url(...) and no default was supplied — the request is incomplete and the builder throws instead of producing a malformed HttpRequest.
Solutions
- Set the URL before executing: builder.url("https://host/path")
- Validate the config/env value feeding the URL is non-null and non-empty at startup
- Guard dynamic URL construction: throw your own descriptive error if baseUrl is blank
- If you only wanted the request shape for logging, still set a placeholder URL or use toCurlCommand() only after url() is called
Example fix
// before
HttpRequestBuilder b = new HttpRequestBuilder(client);
b.invoke(); // throws, url never set
// after
HttpRequestBuilder b = new HttpRequestBuilder(client);
b.url("https://api.example.com/v1/users").invoke(); Defensive patterns
Strategy: validation
Validate before calling
if (baseUrl == null || baseUrl.isEmpty()) throw new IllegalArgumentException('request URL is not configured');
builder.url(baseUrl + path); Prevention
- Always call url() before build()/invoke()/method()/response()
- Validate config/env-provided base URLs at startup
- Fail your own tests early when template substitution yields a blank URL
When it happens
Trigger: Calling build()/invoke()/method()/response() on a builder where url() was never called; passing null to url(); clearing/reset flows that wipe the URL before a second build; using toCurlCommand() on a freshly created builder.
Common situations: Programmatic HTTP calls in Java tests where the URL comes from config/env and the property was empty or missing; template substitution producing empty strings handled as null; copy-pasted builder chains missing the url() line.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- missing argument for multiPart()
- missing argument for file()
- missing argument for files()
- proceed() needs a target URL or Host header in request
- cache() requires (key, fn)
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/26cc2c75259f076b.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/http/HttpRequestBuilder.java:450
segments.addAll(StringUtils.split(item, '/', true));
}
}
builder.setPathSegments(segments);
}
URI uri = builder.build();
return uri.toASCIIString();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
// Destructive: drains multiPart form fields into URL params when method resolves to GET,
// and consumes multiPart into body bytes otherwise. Callers must set method() before
// calling build() on a form/multipart request, or the GET default below will silently
// rewrite the request.
private void buildInternal() {
if (url == null) {
throw new RuntimeException("incomplete http request, 'url' not set");
}
if (method == null) {
if (multiPart != null && multiPart.isMultipart()) {
method = "POST";
} else {
method = "GET";
}
}
method = method.toUpperCase();
if ("GET".equals(method) && multiPart != null) {
Map<String, Object> parts = multiPart.getFormFields();
if (parts != null) {
parts.forEach((k, v) -> param(k, (String) v));
}
multiPart = null;
}
if (multiPart != null) {
if (body == null) { // this is not-null only for a re-try, don't rebuild multi-partView on GitHub (pinned to a22eb90246)