{"record":{"id":"4ed7f75512daffb2","repo":"eclipse-vertx/vert.x","slug":"invalid-escape-sequence-escapesequence","errorCode":null,"errorMessage":"Invalid escape sequence: %${escapeSequence}","messagePattern":"Invalid escape sequence: %(.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"vertx-core/src/main/java/io/vertx/core/internal/net/RFC3986.java","lineNumber":296,"sourceCode":"      // http://tools.ietf.org/html/rfc3986#section-2.4\n      if (path.charAt(start) == '%') {\n        decodeUnreserved(path, start);\n      }\n\n      start++;\n    }\n  }\n\n  private static void decodeUnreserved(StringBuilder path, int start) {\n    if (start + 3 <= path.length()) {\n      // these are latin chars so there is no danger of falling into some special unicode char that requires more\n      // than 1 byte\n      final String escapeSequence = path.substring(start + 1, start + 3);\n      int unescaped;\n      try {\n        unescaped = Integer.parseInt(escapeSequence, 16);\n        if (unescaped < 0) {\n          throw new IllegalArgumentException(\"Invalid escape sequence: %\" + escapeSequence);\n        }\n      } catch (NumberFormatException e) {\n        throw new IllegalArgumentException(\"Invalid escape sequence: %\" + escapeSequence);\n      }\n      // validate if the octet is within the allowed ranges\n      if (\n        // ALPHA\n        (unescaped >= 0x41 && unescaped <= 0x5A) ||\n          (unescaped >= 0x61 && unescaped <= 0x7A) ||\n          // DIGIT\n          (unescaped >= 0x30 && unescaped <= 0x39) ||\n          // HYPHEN\n          (unescaped == 0x2D) ||\n          // PERIOD\n          (unescaped == 0x2E) ||\n          // UNDERSCORE\n          (unescaped == 0x5F) ||\n          // TILDE","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java/io/vertx/core/internal/net/RFC3986.java#L278-L314","documentation":"URI path decoding failure in decodeUnreserved: a percent escape in the path either has non-hex digits or the decoded value is not an unreserved character (it is a reserved/invalid codepoint that must stay escaped per RFC 3986). The offending escape sequence is reported in the message.","triggerScenarios":"Thrown at vertx-core/src/main/java/io/vertx/core/internal/net/RFC3986.java:296 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Keep reserved characters percent-encoded in paths","Fix malformed hex sequences in the source path"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"fb308bd8c3f12c79f4ae89bef67fadf6c80d036e","analyzedAt":"2026-09-06T11:37:12.241Z","contentChangedAt":"2026-09-06T11:37:12.241Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}