apache/dubbo · error · IllegalArgumentException

unterminated escape sequence at index ${i} of: ${str}

Error message

unterminated escape sequence at index ${i} of: ${str}

What it means

Thrown by URLStrParser.parseEncodedParams while scanning a percent-encoded query parameter string. When a '%' is encountered but fewer than two hex digits remain before the end of the string (i + 3 > len), the escape sequence is incomplete and cannot be decoded. This protects the hex decoder from reading past the buffer and surfaces malformed URL-encoded input explicitly.

Source

Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/URLStrParser.java:239

        return parseURLBody(encodedURLStr, decodedBody, parameters);
    }

    private static Map<String, String> parseEncodedParams(String str, int from) {
        int len = str.length();
        if (from >= len) {
            return Collections.emptyMap();
        }

        TempBuf tempBuf = DECODE_TEMP_BUF.get();
        Map<String, String> params = new HashMap<>();
        int nameStart = from;
        int valueStart = -1;
        int i;
        for (i = from; i < len; i++) {
            char ch = str.charAt(i);
            if (ch == '%') {
                if (i + 3 > len) {
                    throw new IllegalArgumentException("unterminated escape sequence at index " + i + " of: " + str);
                }
                ch = (char) decodeHexByte(str, i + 1);
                i += 2;
            }

            switch (ch) {
                case '=':
                    if (nameStart == i) {
                        nameStart = i + 1;
                    } else if (valueStart < nameStart) {
                        valueStart = i + 1;
                    }
                    break;
                case ';':
                case '&':
                    addParam(str, true, nameStart, valueStart, i - 2, params, tempBuf);
                    nameStart = i + 1;
                    break;

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Find the malformed parameter substring reported in the message and fix the truncation, e.g. "k=v%2" -> "k=v%20".
  2. If a literal '%' is intended in a value, URL-encode it as "%25" before building the query string.
  3. Use a well-tested encoder (java.net.URLEncoder or Dubbo's URL.encode) instead of manually inserting '%'.
  4. If the string comes from an external store (registry/DB), re-encode or re-serialize the affected URL entry.

Example fix

// before
String params = "version=1.0%&timeout=1000";  // stray %
Map<String,String> p = URLStrParser.parseEncodedParams(params, 0);
// after
String params = "version=1.0%25&timeout=1000";  // % encoded as %25
Defensive patterns

Strategy: validation

Validate before calling

// Reject parameter strings with a truncated percent escape before parsing
private static final java.util.regex.Pattern BAD_ESCAPE =
    java.util.regex.Pattern.compile("%(?![0-9A-Fa-f]{2})");

boolean escapesAreComplete(String encodedParams) {
    return !BAD_ESCAPE.matcher(encodedParams).find();
}
// if (escapesAreComplete(s)) URLStrParser.parseEncodedParams(s, 0); else fix(s);

Try / catch

try {
    Map<String,String> p = URLStrParser.parseEncodedParams(s, 0);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("unterminated escape sequence")) {
        // s is malformed; log, repair, or reject the offending parameter string
    } else throw e;
}

Prevention

When it happens

Trigger: Passing an encoded parameter string ending in a stray or truncated percent escape to URLStrParser.parseEncodedParams / parseEncodedStr, e.g. "k=v%2", "token=abc%", or a value containing a lone '%' that was not URL-encoded. Also triggered by manual string concatenation of encoded params that drops trailing hex digits.

Common situations: Hand-built query strings where '%' was used literally instead of "%25"; truncation of an encoded URL by loggers/proxies; custom encoders that emit '%' for non-ASCII without following hex; corrupt serialized Dubbo URLs read from registry/zookeeper.

Related errors


AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14). Data as JSON: /api/errors/f69701522bf4d013. Report an issue: GitHub.