{"record":{"id":"cea005bdae9a145d","repo":"karatelabs/karate","slug":"cannot-parse-the-request-uri","errorCode":null,"errorMessage":"cannot parse the request URI: ","messagePattern":"cannot parse the request URI: ","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"karate-core/src/main/java/io/karatelabs/http/HttpServerHandler.java","lineNumber":67,"sourceCode":"\n    HttpServerHandler(HttpServer server) {\n        this.server = server;\n    }\n\n    @Override\n    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) {\n        HttpRequest request;\n        try {\n            request = toRequest(req);\n        } catch (Exception e) {\n            // A malformed REQUEST LINE fails here, before any handler exists to answer it — a bad\n            // percent-escape in the query string (`?state=%zz`) makes Netty's QueryStringDecoder throw\n            // while we are still building the request. This used to escape channelRead0 into the pipeline\n            // tail, which logs the exception and writes NOTHING: the client then waits for a response that\n            // will never come, while the server happily serves every other connection. A hung request is\n            // worse than any wrong status, so say 400 — the client sent something we cannot parse.\n            logger.warn(\"bad request '{}': {}\", req.uri(), e.getMessage());\n            ctx.writeAndFlush(error(HttpResponseStatus.BAD_REQUEST,\n                    \"cannot parse the request URI: \" + e.getMessage()));\n            return;\n        }\n        if (server.wsHandler != null && isWsUpgrade(req)) {\n            try {\n                handleWsUpgrade(ctx, req, request);\n            } catch (Exception e) {\n                String message = e.getMessage();\n                logger.error(\"ws upgrade error: {}\", message);\n                ctx.writeAndFlush(error(message));\n            }\n            return;\n        }\n        if (server.sseHandler != null && isSseRequest(req)) {\n            try {\n                SseConnection connection = new SseConnection(ctx);\n                server.sseHandler.accept(request, connection);\n            } catch (Exception e) {","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/http/HttpServerHandler.java#L49-L85","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n'/callback?state=%zz' // 400 cannot parse the request URI\n// after\n'/callback?state=' + encodeURIComponent(state)","handlingStrategy":"validation","validationCode":"// client-side pre-check in JS\nfunction safeUrl(raw) {\n  try { new URL(raw); return raw; } catch (e) { return encodeURI(raw); }\n}\n// ensure every query param value is encoded: encodeURIComponent(value)","typeGuard":null,"tryCatchPattern":"// server test: assert the mock returns 400 rather than hanging\nresponse = httpGet('/callback?state=%zz');\nassert response.status == 400;","preventionTips":["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"],"tags":["http","netty","bad-request","uri","server"],"backgroundTag":"invalid-url-format","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}