zxing/zxing · error · IllegalArgumentException

illegal character encountered: {stringRepresentation.substri

Error message

illegal character encountered: {stringRepresentation.substring(pos)}

What it means

Thrown by BitMatrix.parse(String, setString, unsetString) when the parser encounters a substring at the current position that matches neither setString nor unsetString, and is not a newline/carriage-return. The exception message includes the unparsed remainder of the string from the failure point.

Source

Thrown at core/src/main/java/com/google/zxing/common/BitMatrix.java:129

          if (rowLength == -1) {
            rowLength = bitsPos - rowStartPos;
          } else if (bitsPos - rowStartPos != rowLength) {
            throw new IllegalArgumentException("row lengths do not match");
          }
          rowStartPos = bitsPos;
          nRows++;
        }
        pos++;
      }  else if (stringRepresentation.startsWith(setString, pos)) {
        pos += setString.length();
        bits[bitsPos] = true;
        bitsPos++;
      } else if (stringRepresentation.startsWith(unsetString, pos)) {
        pos += unsetString.length();
        bits[bitsPos] = false;
        bitsPos++;
      } else {
        throw new IllegalArgumentException(
            "illegal character encountered: " + stringRepresentation.substring(pos));
      }
    }

    // no EOL at end?
    if (bitsPos > rowStartPos) {
      if (rowLength == -1) {
        rowLength = bitsPos - rowStartPos;
      } else if (bitsPos - rowStartPos != rowLength) {
        throw new IllegalArgumentException("row lengths do not match");
      }
      nRows++;
    }

    BitMatrix matrix = new BitMatrix(rowLength, nRows);
    for (int i = 0; i < bitsPos; i++) {
      if (bits[i]) {
        matrix.set(i % rowLength, i / rowLength);

View on GitHub (pinned to 19aa2d8254)

Solutions

  1. Ensure every non-newline character in stringRepresentation is covered by either setString or unsetString — verify token lengths match
  2. Pre-sanitize the input: remove tabs, trim BOM, normalize line endings to '\n'
  3. If the input uses single characters '1'/'0' or '#'/' ', pass single-character setString/unsetString

Example fix

// before
BitMatrix.parse("## ## ##\n## ##  ", "## ", "   ");
// token width mismatch causes illegal character

// after
BitMatrix.parse("10110\n01101", "1", "0");
// single-char tokens, clean newlines
Defensive patterns

Strategy: validation

Validate before calling

static boolean isParseable(String repr, String setStr, String unsetStr) {
    if (repr == null) return false;
    int pos = 0;
    while (pos < repr.length()) {
        char c = repr.charAt(pos);
        if (c == '\n' || c == '\r') { pos++; continue; }
        if (repr.startsWith(setStr, pos)) { pos += setStr.length(); }
        else if (repr.startsWith(unsetStr, pos)) { pos += unsetStr.length(); }
        else return false;
    }
    return true;
}

Prevention

When it happens

Trigger: Calling BitMatrix.parse() where setString and unsetString tokens don't cover all characters in the input — e.g., passing setString="##" and unsetString=" " (two spaces) but the input contains single characters, or the input has stray whitespace, tabs, or punctuation.

Common situations: Mismatch between the token width used in the input string and the setString/unsetString arguments (e.g., single-char input with multi-char tokens or vice versa); non-ASCII whitespace characters in the input; trailing spaces or BOM characters.

Related errors


AI-assisted analysis of zxing/zxing@19aa2d8254 (2026-08-14). Data as JSON: /api/errors/84f8e1cb009ac1fe. Report an issue: GitHub.