{"record":{"id":"4714a7451140b7f7","repo":"apache/hadoop","slug":"illegal-escaped-string-unescaped-at","errorCode":null,"errorMessage":"Illegal escaped string {} unescaped {} at {}","messagePattern":"Illegal escaped string (.+?) unescaped (.+?) at (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/StringUtils.java","lineNumber":760,"sourceCode":"   * unEscapeString.\n   * @param str str.\n   * @param escapeChar escapeChar.\n   * @param charsToEscape array of characters to unescape\n   * @return escape string.\n   */\n  public static String unEscapeString(String str, char escapeChar, \n                                      char[] charsToEscape) {\n    if (str == null) {\n      return null;\n    }\n    StringBuilder result = new StringBuilder(str.length());\n    boolean hasPreEscape = false;\n    for (int i=0; i<str.length(); i++) {\n      char curChar = str.charAt(i);\n      if (hasPreEscape) {\n        if (curChar != escapeChar && !hasChar(charsToEscape, curChar)) {\n          // no special char\n          throw new IllegalArgumentException(\"Illegal escaped string \" + str + \n              \" unescaped \" + escapeChar + \" at \" + (i-1));\n        } \n        // otherwise discard the escape char\n        result.append(curChar);\n        hasPreEscape = false;\n      } else {\n        if (hasChar(charsToEscape, curChar)) {\n          throw new IllegalArgumentException(\"Illegal escaped string \" + str + \n              \" unescaped \" + curChar + \" at \" + i);\n        } else if (curChar == escapeChar) {\n          hasPreEscape = true;\n        } else {\n          result.append(curChar);\n        }\n      }\n    }\n    if (hasPreEscape ) {\n      throw new IllegalArgumentException(\"Illegal escaped string \" + str + ","sourceCodeStart":742,"sourceCodeEnd":778,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/StringUtils.java#L742-L778","documentation":"StringUtils.unEscapeString(str, escapeChar, charsToEscape) processes escape sequences in delimited strings (the standard way Hadoop escapes ',', '=', '\\' in Configuration values). It throws IllegalArgumentException when a character follows the escape char but is neither the escape char itself nor in charsToEscape — an escape that unescapes nothing meaningful.","triggerScenarios":"Parsing configuration values where an input like 'a\\\\z' uses the escape char ('\\\\') before an ordinary character: Windows paths 'C:\\\\tmp' passed with single backslashes, or values escaped by different rules than the parser expects.","commonSituations":"User-supplied config values with stray backslashes; producers that escape a different char set than the consumer's charsToEscape; hand-edited XML values with half-escaped delimiters.","solutions":["Escape every literal escape char in the input (double backslashes on Windows paths: C:\\\\tmp)","Produce values with StringUtils.escapeString(value, escapeChar, sameCharsToEscape) so both sides agree on the format","Validate/normalize input before unescaping and reject unknown escape sequences with a clear message","If a trailing sequence keeps failing, prefer comma-separated values parsed with StringSplitter-style APIs that document their escaping"],"exampleFix":"// before\nString raw = \"C:\\tmp\\\\x\"; // single backslash: '\\t' seen as escaping ordinary 't'\nString v = StringUtils.unEscapeString(raw, '\\\\', new char[]{',', '='});\n\n// after\nString raw = \"C:\\\\tmp\\\\x\"; // every literal backslash doubled\nString v = StringUtils.unEscapeString(raw, '\\\\', new char[]{',', '='});","handlingStrategy":"validation","validationCode":"static boolean isValidEscaped(String s, char esc, char[] toEscape) {\n  String specials = new String(toEscape);\n  for (int i = 0; i < s.length(); i++) {\n    char c = s.charAt(i);\n    if (c == esc) {\n      if (i + 1 >= s.length()) return false;               // dangling escape\n      char n = s.charAt(++i);\n      if (n != esc && specials.indexOf(n) < 0) return false; // escape of ordinary char\n    } else if (specials.indexOf(c) >= 0) {\n      return false;                                         // raw special char\n    }\n  }\n  return true;\n}\n// use: isValidEscaped(value, '\\\\', new char[]{',', '='}) before unEscapeString","typeGuard":null,"tryCatchPattern":"try { StringUtils.unEscapeString(str, esc, chars); } catch (IllegalArgumentException e) { /* message prints str, offending char and index — fix escaping at the producer */ }","preventionTips":["Always create escaped strings with StringUtils.escapeString(value, esc, sameChars) — never hand-escape","Keep the escape char and charsToEscape set identical on producer and consumer sides","Double every literal backslash (Windows paths) before embedding values in escaped config strings","Round-trip test: unEscapeString(escapeString(x)) == x for every value your app writes"],"tags":["hadoop","stringutils","escaping","configuration","illegalargument"],"backgroundTag":"invalid-escape-sequence","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}