oobabooga/textgen · warning · RuntimeError

unknown escape at {src}

Error message

unknown escape at {src}

What it means

Raised by parse_char (modules/grammar/grammar_utils.py:136): inside a quoted literal, a backslash escape is followed by a letter the GBNF parser does not recognize. Supported escapes are \" \[ \] \\ \- \r \n \t \xHH \uHHHH \UHHHHHHHH; anything else (\d, \w, \s, \', \0) hits the RuntimeError.

Source

Thrown at modules/grammar/grammar_utils.py:136

    if src[0] == "\\":
        esc = src[1]
        if esc == "x":
            return read_hex(src[2:4]), src[4:]
        elif esc == "u":
            return read_hex(src[2:6]), src[6:]
        elif esc == "U":
            return read_hex(src[2:10]), src[10:]
        elif esc in ('"', "[", "]", "\\", "-"):
            return esc, src[2:]
        elif esc == "r":
            return "\r", src[2:]
        elif esc == "n":
            return "\n", src[2:]
        elif esc == "t":
            return "\t", src[2:]
        elif esc == "\\":
            return "\\", src[2:]
        raise RuntimeError("unknown escape at " + src)
    elif src:
        return src[0], src[1:]
    raise RuntimeError("unexpected end of input")


def parse_sequence(state, src, rule_name, outbuf, is_nested):
    out_start_pos = len(outbuf)

    # sequence size, will be replaced at end when known
    outbuf.append(TO_BE_FILLED_MARKER)

    last_sym_start = len(outbuf)
    remaining_src = src
    while remaining_src:
        if remaining_src[0] == '"':  # literal string
            remaining_src = remaining_src[1:]
            last_sym_start = len(outbuf)
            while remaining_src[0] != '"':

View on GitHub (pinned to ed888c71f2)

Solutions

  1. Replace regex escapes with GBNF constructs: \d -> [0-9], \w -> [a-zA-Z0-9_], \s -> [ \t\r\n].
  2. For quotes/brackets inside literals use the supported list: \", \[, \], \\, \- or hex \xHH for anything else.
  3. After editing, run the grammar through the parser once before attaching it to a generation request.

Example fix

// before
num ::= "\d+"

// after
num ::= [0-9]+
Defensive patterns

Strategy: validation

Validate before calling

import re

SUPPORTED_ESCAPE = re.compile(r'\\(?:["\[\]\\\-rnt]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})')
UNSUPPORTED = re.compile(r'\\(?!["\[\]\\\-rntxuU])')

def no_regex_escapes(grammar: str) -> bool:
    return not UNSUPPORTED.search(grammar)

Try / catch

try:
    parse_grammar(grammar_text)
except RuntimeError as e:
    if 'unknown escape' in str(e):
        raise ValueError('Grammar uses a non-GBNF escape (regex-style \\d/\\w/\\s?); rewrite with character classes') from None
    raise

Prevention

When it happens

Trigger: A grammar literal using regex-style escapes, e.g. root ::= "a\d+" or "\wword"; escaping a quote with \' instead of \"; using \0 for NUL instead of \x00.

Common situations: Porting a regex to GBNF and keeping regex escapes verbatim; JSON-sourced grammars where double-escaping got mangled; assumption that PCRE escapes work in GBNF.

Related errors


AI-assisted analysis of oobabooga/textgen@ed888c71f2 (2026-08-15). Data as JSON: /api/errors/3c4d0a85417fcdb9. Report an issue: GitHub.