apple/pkl · error · ParserError
unexpectedEndOfFile
unexpectedEndOfFile
Error message
Unexpected end of file.
What it means
The Pkl parser reached the end of the input file while it still expected more tokens — for example in the middle of an expression, argument list, or identifier reference. The parser throws this instead of a generic unexpected-token error when the lookahead token is EOF, because the real problem is missing input, not wrong input. It points at the position one past the last parsed token.
Solutions
- Scan the source at the reported stop position and close the nearest unclosed bracket, paren, or quote above it
- Check for a trailing incomplete expression (e.g. a dangling operator or arrow) and complete or remove it
- Verify the file was fully written/transferred — compare byte size or re-save the source
- If generating Pkl programmatically, assert balanced delimiters before invoking the parser
Example fix
// before (truncated) x = foo( // after x = foo(1, 2)
Defensive patterns
Strategy: try-catch
Validate before calling
function checkBalancedDelimiters(src) {
const pairs = {'{':'}','(':')','[':']'};
const stack = [];
let inStr = false, esc = false;
for (const ch of src) {
if (esc) { esc = false; continue; }
if (ch === '\\') { esc = true; continue; }
if (ch === '"') { inStr = !inStr; continue; }
if (inStr) continue;
if (pairs[ch]) stack.push(pairs[ch]);
else if (Object.values(pairs).includes(ch) && stack.pop() !== ch) return false;
}
return !inStr && stack.length === 0;
}
// run before invoking the parser; abort if false Type guard
null
Try / catch
try {
const result = pkl.evaluateSource(src);
} catch (e) {
if (e instanceof ParserError && e.errorId === 'unexpectedEndOfFile') {
// append missing closers or report position e.span.start
} else { throw e; }
} Prevention
- Lint source for balanced brackets/quotes before parsing
- Never truncate generated Pkl output — write files atomically
- Use an editor with Pkl syntax highlighting to catch unclosed delimiters early
When it happens
Trigger: Calling the parser (e.g. via pkl.evaluateSource / ParserImpl.parse) on source that ends prematurely: an unclosed `{`, `(`, `[`, or string literal, a trailing operator like `1 +`, a dangling `->` in a type, or a truncated file passed in.
Common situations: Files cut off by an incomplete download or failed save; copy-pasting a snippet and dropping the closing brace; generating Pkl code programmatically and emitting an unbalanced delimiter; heredoc/template tooling swallowing the final lines.
Related errors
- '" + ch + "'
- closingStringDelimiterMustBeginOnNewLine
- closingStringDelimiterMustBeginOnNewLine
- ':'
- ErrorMessages.create(errorKey, args)
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/d01a138bc4dc2126.
Report an issue: GitHub.
Appendix: source
Thrown at pkl-parser/src/main/java/org/pkl/parser/ParserImpl.java:1040
var tk = next();
yield new FloatLiteralExpr(tk.text(lexer), tk.span);
}
case STRING_START -> parseSingleLineStringLiteralExpr();
case STRING_MULTI_START -> parseMultiLineStringLiteralExpr();
case IDENTIFIER -> {
var identifier = parseIdentifier();
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));View on GitHub (pinned to f3efcbfc9b)