apple/pkl · error · ParserError

unexpectedCharacter

unexpectedCharacter

Error message

Unexpected character `{0}`. Did you mean `{1}`?

What it means

A unicode escape `\u` must be followed by `{codepoint}` in braces. When the lexer reaches lexUnicodeEscape and the lookahead is not `{`, it throws unexpectedCharacter suggesting `{`. This means the `u` of `\u` was consumed (via lexEscape) but the required opening brace is missing or replaced by something else.

Source

Thrown at pkl-parser/src/main/java/org/pkl/parser/Lexer.java:495

              c - 2,
              cursor - c + 2);

        throw lexError(
            ErrorMessages.create("invalidCharacterEscapeSequence", "\\" + (char) ch, "\\"),
            c - 2,
            2);
      }
      default ->
          throw lexError(
              ErrorMessages.create("invalidCharacterEscapeSequence", "\\" + (char) ch, "\\"),
              cursor - 2,
              2);
    };
  }

  private Token lexUnicodeEscape() {
    if (lookahead != '{') {
      throw unexpectedChar(lookahead, "{");
    }
    do {
      nextChar();
    } while (lookahead != '}' && lookahead != EOF && Character.isLetterOrDigit(lookahead));
    if (lookahead == '}') {
      // consume the close bracket
      nextChar();
    } else {
      throw lexError(ErrorMessages.create("unterminatedUnicodeEscapeSequence", text()), span());
    }
    return Token.STRING_ESCAPE_UNICODE;
  }

  private Token lexIdentifier() {
    while (isIdentifierPart(lookahead)) {
      nextChar();
    }

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Wrap the codepoint in braces: `\u{41}` instead of `\u41`.
  2. Re-check every `\u` in the file and ensure each is followed by `{`.
  3. If a literal `u` was meant, escape the backslash: `\\u`.
  4. For fixed 4-digit escapes coming from JSON, convert programmatically to the braced form.

Example fix

// before
arrow = "\u2192"
// after
arrow = "\u{2192}"
Defensive patterns

Strategy: validation

Validate before calling

function unbracedUnicode(src) { return /\\u(?!\{)/.test(src); }
if (unbracedUnicode(src)) throw new Error('Unicode escapes must be \u{...}, not \uXXXX');

Type guard

null

Try / catch

try { tokens = lexer.next(); } catch (e) { if (e.code === 'unexpectedCharacter' && /\\u/.test(e.message ?? '')) { console.error('Wrap unicode codepoint in braces: \u{...}'); } throw e; }

Prevention

When it happens

Trigger: lexEscape → lexUnicodeEscape: the string contains `\u` followed by a character other than `{`, e.g. `\u0041`, `\u41`, or `\u"`. Only `\u{...}` is valid.

Common situations: Habit from Java/Python/C where `\u0041` or `\uXXXX` is the standard syntax; converting escapes from JSON (`\u0041`) into Pkl; truncation where `{` was deleted leaving `\u` before a letter or quote.

Related errors


AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08). Data as JSON: /api/errors/07d9a90f81a3ea5c. Report an issue: GitHub.