{"record":{"id":"00ada86a286ccc4f","repo":"apache/beam","slug":"not-in-legal-encoded-format-substring-i-i-2-not-in-format-xx","errorCode":null,"errorMessage":"not in legal encoded format; substring [{i}..{i+2}] not in format \"%xx\"","messagePattern":"not in legal encoded format; substring \\[(.+?)\\.\\.(.+?)\\] not in format \"%xx\"","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/util/StringUtils.java","lineNumber":71,"sourceCode":"    return sb.toString();\n  }\n\n  /**\n   * Converts the given string, encoded using {@link #byteArrayToJsonString}, into a byte array.\n   *\n   * @throws IllegalArgumentException if the argument string is not legal\n   */\n  public static byte[] jsonStringToByteArray(String string) {\n    List<Byte> bytes = new ArrayList<>();\n    for (int i = 0; i < string.length(); ) {\n      char c = string.charAt(i);\n      Byte b;\n      if (c == '%') {\n        // Escaped.  Expect '%xx' format.\n        try {\n          b = (byte) Integer.parseInt(string.substring(i + 1, i + 3), 16);\n        } catch (IndexOutOfBoundsException | NumberFormatException exn) {\n          throw new IllegalArgumentException(\n              \"not in legal encoded format; \"\n                  + \"substring [\"\n                  + i\n                  + \"..\"\n                  + (i + 2)\n                  + \"] not in format \\\"%xx\\\"\",\n              exn);\n        }\n        i += 3;\n      } else {\n        // Send through unchanged.\n        b = (byte) c;\n        i++;\n      }\n      bytes.add(b);\n    }\n    byte[] byteArray = new byte[bytes.size()];\n    int i = 0;","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/util/StringUtils.java#L53-L89","documentation":"StringUtils.jsonStringToByteArray decodes strings where bytes are escaped as '%xx'. When it encounters a '%' that is not followed by two hex digits, it throws this IllegalArgumentException. The input string is not in the escaped encoded format the function expects.","triggerScenarios":"Calling jsonStringToByteArray on a string containing a '%' at index i where substring(i+1, i+3) is shorter than two characters or is not valid hex (e.g. \"100%\", \"%G1\", \"%a\", or a raw unescaped percent in a filename).","commonSituations":"Passing plain file names or user strings containing literal '%' through Beam's JSON-string escaping path (e.g. WindowedFilenamePolicy or dynamic destinations) instead of pre-escaped values; hand-built escaped strings with malformed escapes.","solutions":["Escape '%' characters correctly before calling, using the matching byteArrayToJsonString method, so every '%' is followed by two hex digits.","Validate that each '%' in the input is followed by exactly two hex characters before invoking jsonStringToByteArray.","If the input is raw user data (e.g. a filename with '%'), sanitize or percent-encode it first.","Ensure you are not double-processing a string that was already decoded (a lone '%' remains)."],"exampleFix":"// before\nbyte[] bytes = StringUtils.jsonStringToByteArray(\"100% done\"); // '%' not followed by hex\n// after\nString escaped = StringUtils.byteArrayToJsonString(\"100% done\".getBytes(StandardCharsets.UTF_8));\nbyte[] bytes = StringUtils.jsonStringToByteArray(escaped); // round-trips correctly","handlingStrategy":"validation","validationCode":"static boolean isLegalEscapedFormat(String s) {\n  for (int i = 0; i < s.length(); i++) {\n    if (s.charAt(i) == '%' && (i + 2 >= s.length()\n        || !isHex(s.charAt(i + 1)) || !isHex(s.charAt(i + 2)))) {\n      return false;\n    }\n  }\n  return true;\n}","typeGuard":null,"tryCatchPattern":"try {\n  bytes = StringUtils.jsonStringToByteArray(s);\n} catch (IllegalArgumentException e) {\n  // re-escape input and retry\n}","preventionTips":["Always produce escaped strings via byteArrayToJsonString rather than hand-concatenation.","Sanitize user-provided filenames/strings containing '%' before passing to Beam escaping utilities.","Add a pre-check that every '%' is followed by two hex digits."],"tags":["beam","encoding","string-parsing","format"],"backgroundTag":"invalid-argument-format","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}