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
- Find the malformed parameter substring reported in the message and fix the truncation, e.g. "k=v%2" -> "k=v%20".
- If a literal '%' is intended in a value, URL-encode it as "%25" before building the query string.
- Use a well-tested encoder (java.net.URLEncoder or Dubbo's URL.encode) instead of manually inserting '%'.
- 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
- Never build percent-encoded strings by hand; use java.net.URLEncoder or Dubbo's URL.encode.
- If you need a literal '%' in a value, encode it as "%25".
- Validate encoded input with a regex like "^(?:[^%]|%[0-9A-Fa-f]{2})*$" before decoding.
- Treat truncated escapes from external stores (registry/DB) as data corruption and re-serialize.
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
- bytes2base64: length < 0, length is {}
- bytes2base64: offset + length > array length.
- hex string format error [${c}].
- invalid hex byte '%s' at index %d of '%s'
- type [ ${type} ] is unsupported
AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14).
Data as JSON: /api/errors/f69701522bf4d013.
Report an issue: GitHub.