oracle/graal · error · UnsupportedRegexException

Literal escape not supported in this context

Error message

Literal escape not supported in this context

What it means

Thrown when the \Q...\E quoting escape appears in a context where the Java-flavor lexer resolves single-character escapes (parseCustomCharEscape), most notably inside a character class. Outside classes \Q is handled as a multi-char construct in parseCustomEscape, but inside [...] the lexer reaches case 'Q' of the single-char escape parser and rejects it, because quoted literal strings cannot be represented as a charset range there.

Source

Thrown at regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/flavor/java/JavaRegexLexer.java:880

                    int i = position;
                    if (!findChars('}')) {
                        throw syntaxError(JavaErrorMessages.UNCLOSED_CHAR_NAME, ErrorCode.InvalidEscape);
                    }
                    advance(); // skip '}'
                    String name = pattern.substring(i, position - 1);
                    try {
                        return Character.codePointOf(name);
                    } catch (IllegalArgumentException x) {
                        throw syntaxError(JavaErrorMessages.unknownCharacterName(name), ErrorCode.InvalidEscape);
                    }
                }
                throw syntaxError(JavaErrorMessages.ILLEGAL_CHARACTER_NAME, ErrorCode.InvalidEscape);
            case 'a':
                return 0x7;
            case 'e':
                return 0x1b;
            case 'Q':
                throw new UnsupportedRegexException("Literal escape not supported in this context");
            default:
                return -1;
        }
    }

    private int parseUnicodeHexEscape() {
        if (consumingLookahead(RegexLexer::isHexDigit, 4)) {
            return Integer.parseInt(pattern, position - 4, position, 16);
        }
        throw syntaxError(JavaErrorMessages.ILLEGAL_UNICODE_ESC_SEQ, ErrorCode.InvalidEscape);
    }

    @Override
    protected int parseCustomEscapeCharFallback(int c, boolean inCharClass) {
        // any non-alphabetic character can be used after an escape
        // digits are not accepted here since they should have been parsed as octal sequence or
        // backreference earlier
        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) {

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Escape each character individually with Pattern.quote-style logic or a per-char backslash escape instead of \Q...\E inside the class
  2. Move the quoted literal out of the character class: match it as an alternation branch (?:\\Qliteral\\E) rather than inside [...]
  3. Pre-compute the escaped class contents (e.g. escape '-', ']', '^', '\\') when building the pattern string dynamically

Example fix

// before
String p = "[\\Qa-b*c\\E]";

// after
String p = "[a\\-b*c]"; // escape metacharacters individually
Defensive patterns

Strategy: validation

Validate before calling

boolean hasQInCharClass(String pattern) {
    return java.util.regex.Pattern.compile("\\[[^\\]]*\\\\Q").matcher(pattern).find();
}

Try / catch

try {
    RegexObject re = compileJavaFlavor(pattern);
} catch (UnsupportedRegexException e) {
    // \Q...\E in a character class: escape members individually and recompile
}

Prevention

When it happens

Trigger: Compiling a Java-flavor pattern with \Q...\E inside a character class, e.g. "[\\Qa-b\\E]" or "[\\Q.*+?\\E]". While lexing the class contents, parseCustomEscape dispatches to the char-escape path, case 'Q' throws UnsupportedRegexException('Literal escape not supported in this context').

Common situations: Patterns that quote a user-supplied literal into a character class to 'safely' include metacharacters; code generated from templates that wraps arbitrary strings in \Q...\E regardless of whether the insertion point is inside [...]; java.util.regex accepts [\Q...\E], so the same pattern works on the JDK but fails on TRegex.

Related errors


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/9fab163ce933ae39. Report an issue: GitHub.