apple/pkl · error · ParserError
unexpectedTokenForExpression
unexpectedTokenForExpression
Error message
Unexpected token `{0}`. What it means
Expression-level parse failure without a specific expectation: a token appeared where an expression was required (or where no particular token was mandated). The parser throws "Unexpected token `{0}`" when it cannot continue parsing an expression and has no expectation to report.
Solutions
- Remove the offending token if it's stray punctuation (`;`, `,`, `)` that has no opener).
- Supply the missing expression (e.g. after `=` or an operator that ended the previous line).
- Insert the intended operator between two juxtaposed expressions (`+`, `.`, whitespace-amend only where valid).
- Check the previous line for an accidentally deleted operator or operand that shifted tokens out of place.
Example fix
// before x = y = 2 // after x = 1 y = 2
Defensive patterns
Strategy: try-catch
Validate before calling
// Flag lines that begin with tokens that cannot start an expression
const BAD_EXPR_START = /^\s*[),;]+|^[*/%]|^&&|^\|\|/;
function linesNotStartingAnExpression(lines) {
return lines.map((l, i) => [l, i]).filter(([l]) => BAD_EXPR_START.test(l)).map(([, i]) => i + 1);
} Try / catch
try {
return parsePkl(src);
} catch (e) {
if (/^Unexpected token `/.test(e.message) && !/Expected `/.test(e.message)) {
throw new Error('Expression expected near ' + e.span + ': remove stray punctuation or supply the missing operand: ' + e.message);
}
throw e;
} Prevention
- Don't carry over `;` and stray `,` from JSON/Java.
- Always give assignments a right-hand side.
- When wrapping lines, keep the operator at the end of the continued line.
When it happens
Trigger: Starting a line with a token that cannot begin an expression (e.g. `)`, `,`, `=>`, an operator like `*` or `&&`); two expressions juxtaposed without an operator; malformed constructs such as `x = ;` or an empty right-hand side of `=`.
Common situations: Stray commas or semicolons carried over from JSON/Java habits; accidentally deleting the right-hand side of an assignment; line-continuation mistakes where an operator from the previous line was dropped.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- danglingDocComment
- danglingDocComment
- ErrorMessages.create(errorKey, args)
- invalidTopLevelToken
- invalidTopLevelToken
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/ee83d4cf4c78eb98.
Report an issue: GitHub.
Appendix: source
Thrown at pkl-parser/src/main/java/org/pkl/parser/ParserImpl.java:1047
if (lookahead == Token.LPAREN
&& !precededBySemicolon
&& _lookahead.newLinesBetween == 0) {
var args = parseArgumentList();
yield new UnqualifiedAccessExpr(
identifier, args, identifier.span().endWith(args.span()));
} else {
yield new UnqualifiedAccessExpr(identifier, null, identifier.span());
}
}
case EOF ->
throw new ParserError(
ErrorMessages.create("unexpectedEndOfFile"), prev.span.stopSpan().move(1));
default -> {
var text = _lookahead.text(lexer);
if (expectation != null) {
throw parserError("unexpectedToken", text, expectation);
}
throw parserError("unexpectedTokenForExpression", text);
}
};
return parseExprRest(expr);
}
@SuppressWarnings("DuplicatedCode")
private Expr parseExprRest(Expr expr) {
// non-null
if (lookahead == Token.NON_NULL) {
var end = next().span;
var res = new NonNullExpr(expr, expr.span().endWith(end));
return parseExprRest(res);
}
// amends
if (lookahead == Token.LBRACE) {
if (expr instanceof ParenthesizedExpr
|| expr instanceof AmendsExpr
|| expr instanceof NewExpr) {View on GitHub (pinned to f3efcbfc9b)