zaproxy/zaproxy · error · URIException

Invalid query

Error message

Invalid query

What it means

In escaped mode (true passed to the constructor / parseUriReference) the query string after '?' is validated against the allowed query character set (uric). If it contains characters that are neither allowed nor properly percent-escaped, URIException("Invalid query") is thrown.

Source

Thrown at zap/src/main/java/org/apache/commons/httpclient/URI.java:2159

        String charset = getProtocolCharset();

        /*
         * Parse the query component.
         * <p><blockquote><pre>
         *  query     =  $7 = <undefined>
         *                                        @@@@@@@@@
         *  ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
         * </pre></blockquote><p>
         */
        if (0 <= at && at + 1 < length && tmp.charAt(at) == '?') {
            int next = tmp.indexOf('#', at + 1);
            if (next == -1) {
                next = tmp.length();
            }
            if (escaped) {
                _query = tmp.substring(at + 1, next).toCharArray();
                if (!validate(_query, uric)) {
                    throw new URIException("Invalid query");
                }
            } else {
                _query = encode(tmp.substring(at + 1, next), allowed_query, charset);
            }
            at = next;
        }

        /*
         * Parse the fragment component.
         * <p><blockquote><pre>
         *  fragment  =  $9 = Related
         *                                                   @@@@@@@@
         *  ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
         * </pre></blockquote><p>
         */
        if (0 <= at && at + 1 <= length && tmp.charAt(at) == '#') {
            if (at + 1 == length) { // empty fragment
                _fragment = "".toCharArray();

View on GitHub (pinned to 9d1970a436)

Solutions

  1. Percent-encode the query parameters (URLEncoder.encode / URIUtil.encode) before constructing the URI, or use the non-escaped constructor so the library encodes them.
  2. Replace raw spaces with %20 and encode non-ASCII characters in the query.
  3. Verify you picked the right constructor variant (escaped vs unescaped) for your input.

Example fix

// before
URI uri = new URI("http://example.com/search?q=" + term, true); // term = "hello world" -> Invalid query
// after
String encoded = java.net.URLEncoder.encode(term, "UTF-8");
URI uri = new URI("http://example.com/search?q=" + encoded, true);
// or let the library encode:
URI uri = new URI("http://example.com/search?q=" + term, false);
Defensive patterns

Strategy: validation

Validate before calling

String encodeQuery(String raw) throws java.io.UnsupportedEncodingException {
    return java.net.URLEncoder.encode(raw, "UTF-8");
}
// encode every name and value BEFORE building the query string

Type guard

boolean isEscapedQuery(String q) {
    return q != null && q.matches("[A-Za-z0-9-._~%!$&'()*+,;=:@/?#]*");
}

Try / catch

try {
    URI uri = new URI(url, true);
} catch (URIException e) {
    if ("Invalid query".equals(e.getMessage())) {
        // rebuild with URLEncoder.encode on each parameter and retry once
    } else { throw e; }
}

Prevention

When it happens

Trigger: new URI("http://host/path?q=a b") or any query containing raw spaces, '<', '>', '"', '{', '}', '|', '\\', '^', '`' or non-ASCII characters while the escaped=true constructor is used, so the library validates instead of encoding.

Common situations: Building URLs by string concatenation with unencoded user input or search terms; non-ASCII (e.g. Chinese/Cyrillic) query parameters pasted in; query strings copied from logs that were partially decoded; using the escaped constructor with a not-yet-escaped URL.

Related errors


AI-assisted analysis of zaproxy/zaproxy@9d1970a436 (2026-09-05). Data as JSON: /api/errors/6c2a6af45812003c. Report an issue: GitHub.