apple/pkl · error · GenericParserError

Unexpected token ` `. Expected ` `.

Error message

Unexpected token `{0}`. Expected `{1}`.

What it means

This is the expect() fast-fail path in GenericParserImpl: when a specific token type is required but absent, the parser throws an unexpectedToken error. For keys starting with "unexpectedToken", the actual lookahead text (or "EOF") is prepended to the message args, so the developer sees what was found versus what was expected.

Solutions

  1. Inspect the reported token and insert or replace it with the expected token listed in the message.
  2. Check the line above the error position — mismatches are often caused by the preceding construct not being closed.
  3. Format the file with the Pkl formatter to normalize punctuation and reveal the structural break.

Example fix

// before (missing '=')
x 1

// after
x = 1
Defensive patterns

Strategy: try-catch

Try / catch

try {
  pklEval(sourceFile);
} catch (PklParseError e) {
  if (e.code === "unexpectedToken") {
    // e.message looks like: Unexpected token `X`. Expected `Y`.
    console.error(`Syntax fix needed near ${e.span}: ${e.message}`);
  } else throw e;
}

Prevention

When it happens

Trigger: Any grammar production calling expect(Token, ...) where the input deviates — e.g. a missing `=`, `}`, `)`, or `,` at the reported position; or the input ends prematurely (lookahead == EOF).

Common situations: Hand-edited Pkl files with a dropped operator or bracket; merging conflicts resolved incorrectly; generated Pkl missing a separator between members.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at pkl-parser/src/main/java/org/pkl/parser/GenericParserImpl.java:1418

    }
    children.add(makeTerminal(next())); // string end
    return new Node(NodeType.STRING_CHARS, children);
  }

  private FullToken expect(Token type, String errorKey, Object... messageArgs) {
    if (lookahead != type) {
      var span = spanLookahead;
      if (lookahead == Token.EOF || _lookahead.newLinesBetween > 0) {
        // don't point at the EOF or the next line, but at the end of the last token
        span = prev().span.stopSpan();
      }
      var args = messageArgs;
      if (errorKey.startsWith("unexpectedToken")) {
        args = new Object[messageArgs.length + 1];
        args[0] = lookahead == Token.EOF ? "EOF" : _lookahead.text(lexer);
        System.arraycopy(messageArgs, 0, args, 1, messageArgs.length);
      }
      throw parserError(ErrorMessages.create(errorKey, args), span);
    }
    return next();
  }

  private void expect(Token type, List<Node> children, String errorKey, Object... messageArgs) {
    var tk = expect(type, errorKey, messageArgs);
    children.add(makeTerminal(tk));
  }

  private void parseListOf(Token terminator, List<Node> children, Supplier<Node> parser) {
    children.add(parser.get());
    ff(children);
    while (lookahead == Token.COMMA) {
      // don't store the last comma
      var comma = makeTerminal(next());
      if (lookahead() == terminator) break;
      children.add(comma);
      ff(children);

View on GitHub (pinned to f3efcbfc9b)