apple/pkl · error · ParserError
invalidTopLevelToken
invalidTopLevelToken
Error message
Invalid token at position. Expected a class, typealias, method, or property.
What it means
The parser encountered a token at module-member position that cannot start a class, typealias, method, or property. After ruling out keywords and doc comments, parseModuleMember throws "Invalid token at position" as the final fallback for any other unexpected token at top level.
Solutions
- Verify the token is at module level intentionally — most often an extra `}` closed the enclosing class/module scope early.
- Start members with a valid declaration: `name = expr`, `name: Type`, `function f() {...}`, `class X {}`, or `typealias Y = ...`.
- Move expressions inside an object body or assign them to a property.
- Check brace balance in the preceding code with an editor's bracket matching.
Example fix
// before (brace closed class early)
class Bird {
name: String
}
fly = true // invalid at top level inside module member position
// after
class Bird {
name: String
fly = true
} Defensive patterns
Strategy: validation
Validate before calling
// Flag top-level lines that cannot start a module member
const MEMBER_START = /^\s*(class\b|typealias\b|function\b|amends\b|extends\b|import\b|`?[A-Za-z_]\w*`?\s*(:|=|\())/;
function invalidTopLevelLines(lines) {
return lines.map((l, i) => [l.trim(), i])
.filter(([l]) => l && !l.startsWith('//') && !MEMBER_START.test(l))
.map(([, i]) => i + 1);
} Prevention
- Keep every top-level line a declaration, assignment-property, import, or header.
- Match braces so members never fall outside their class/object scope.
- Never paste object-body entries at module level.
When it happens
Trigger: Statements at top level that Pkl doesn't allow (e.g. bare expressions, `new` blocks, stray `}` or `,`); object-body-only syntax like `x { ... }` amending without `=` used at module level in a way the grammar rejects; an operator or punctuation starting a line at module scope.
Common situations: Copy-pasting object-body entries outside of any object; an extra closing brace ending the enclosing class early so following members land at top level; expressions written where declarations are required.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/481a12b72e4e9a9b.
Report an issue: GitHub.
Appendix: source
Thrown at pkl-parser/src/main/java/org/pkl/parser/ParserImpl.java:356
case CLASS -> {
var node = parseClass(header);
nodes.add(node);
return node.span();
}
case FUNCTION -> {
var node = parseClassMethod(header);
nodes.add(node);
return node.span();
}
case EOF -> throw parserError("unexpectedEndOfFile");
default -> {
if (lookahead.isKeyword()) {
throw parserError("keywordNotAllowedHere", lookahead.text());
}
if (lookahead == Token.DOC_COMMENT) {
throw parserError("danglingDocComment");
}
throw parserError("invalidTopLevelToken");
}
}
}
private TypeAlias parseTypeAlias(MemberHeader header) {
var typeAlias = next().span;
var startSpan = header.span(typeAlias);
var identifier = parseIdentifier();
TypeParameterList typePars = null;
if (lookahead == Token.LT) {
typePars = parseTypeParameterList();
}
expect(Token.ASSIGN, "unexpectedToken", "=");
var type = parseType();
var children =
new ArrayList<@Nullable Node>(header.annotations.size() + header.modifiers.size() + 5);
children.add(header.docComment);View on GitHub (pinned to f3efcbfc9b)