karatelabs/karate · warning
cannot parse the request URI:
Error message
cannot parse the request URI:
What it means
The embedded Karate HTTP server failed while Netty was decoding the request URI/query string (e.g. a bad percent-escape like `?state=%zz`). Previously this exception escaped channelRead0 into the pipeline tail, so no response was written and the client hung; the handler now catches it and replies 400 Bad Request with the decoder's message. It is a server-side guard against malformed request lines.
Solutions
- Fix the client to percent-encode the URI/query correctly (use a URL builder / encodeURIComponent)
- Reproduce the failing URL and inspect the exact decode error in the server's warn log
- If the request comes from a third-party redirect flow, encode query params once, not twice
- If the request is intentionally malformed and you just need it handled, add a custom handler or treat the 400 as the expected result
Example fix
// before '/callback?state=%zz' // 400 cannot parse the request URI // after '/callback?state=' + encodeURIComponent(state)
Defensive patterns
Strategy: validation
Validate before calling
// client-side pre-check in JS
function safeUrl(raw) {
try { new URL(raw); return raw; } catch (e) { return encodeURI(raw); }
}
// ensure every query param value is encoded: encodeURIComponent(value) Try / catch
// server test: assert the mock returns 400 rather than hanging
response = httpGet('/callback?state=%zz');
assert response.status == 400; Prevention
- Always URL-encode query parameter values (encodeURIComponent / URLEncoder)
- Never build URIs by raw string concatenation of user data
- Avoid double-encoding params in OAuth/OIDC redirect flows
- Add a mock-server test for malformed URIs asserting a fast 400
When it happens
Trigger: Sending an HTTP request to a Karate-embedded (mock/proxy) server whose URI contains invalid percent-encoding, illegal characters in the query string, or otherwise unparsable URI syntax that makes Netty's QueryStringDecoder throw.
Common situations: Mock-server tests driven by misconfigured OAuth/OIDC callbacks where `state` or `redirect_uri` params are double-encoded or contain raw `%`; fuzzing tools; clients building URLs manually without URL-encoding.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- waitForHttp() needs a URL argument
- HTTP endpoint not available
- failed to create server SSL context
- failed to generate self-signed certificate
- failed to generate Netty SSL context
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/cea005bdae9a145d.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/http/HttpServerHandler.java:67
HttpServerHandler(HttpServer server) {
this.server = server;
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) {
HttpRequest request;
try {
request = toRequest(req);
} catch (Exception e) {
// A malformed REQUEST LINE fails here, before any handler exists to answer it — a bad
// percent-escape in the query string (`?state=%zz`) makes Netty's QueryStringDecoder throw
// while we are still building the request. This used to escape channelRead0 into the pipeline
// tail, which logs the exception and writes NOTHING: the client then waits for a response that
// will never come, while the server happily serves every other connection. A hung request is
// worse than any wrong status, so say 400 — the client sent something we cannot parse.
logger.warn("bad request '{}': {}", req.uri(), e.getMessage());
ctx.writeAndFlush(error(HttpResponseStatus.BAD_REQUEST,
"cannot parse the request URI: " + e.getMessage()));
return;
}
if (server.wsHandler != null && isWsUpgrade(req)) {
try {
handleWsUpgrade(ctx, req, request);
} catch (Exception e) {
String message = e.getMessage();
logger.error("ws upgrade error: {}", message);
ctx.writeAndFlush(error(message));
}
return;
}
if (server.sseHandler != null && isSseRequest(req)) {
try {
SseConnection connection = new SseConnection(ctx);
server.sseHandler.accept(request, connection);
} catch (Exception e) {View on GitHub (pinned to a22eb90246)