emberjs/ember.js · error
Attempted to parse a path expression, but it was not valid.
Error message
Attempted to parse a path expression, but it was not valid. Paths must start with a-z or A-Z.
What it means
For regular (non-@, non-data) paths, the parser shifts the head segment; if the path has no leading head it cannot be resolved as a variable, so the parser throws. Valid plain paths must start with a letter a-z or A-Z (e.g. this.foo, items, someVar) — the head becomes a variable reference (b.var).
Source
Thrown at packages/@glimmer/syntax/lib/parser/handlebars-node-visitors.ts:471
if (head === undefined) {
throw generateSyntaxError(
`Attempted to parse a path expression, but it was not valid. Paths beginning with @ must start with a-z.`,
this.source.spanFor(path.loc)
);
}
pathHead = b.atName({
name: `@${head}`,
loc: this.source.spanFor({
start: path.loc.start,
end: { line: path.loc.start.line, column: path.loc.start.column + head.length + 1 },
}),
});
} else {
const head = parts.shift();
if (head === undefined) {
throw generateSyntaxError(
`Attempted to parse a path expression, but it was not valid. Paths must start with a-z or A-Z.`,
this.source.spanFor(path.loc)
);
}
pathHead = b.var({
name: head,
loc: this.source.spanFor({
start: path.loc.start,
end: { line: path.loc.start.line, column: path.loc.start.column + head.length },
}),
});
}
return b.path({
head: pathHead,
tail: parts,
loc: this.source.spanFor(path.loc),View on GitHub (pinned to 26f97246a8)
Solutions
- Provide the intended variable name at the indicated location: replace the empty/invalid path with a real identifier starting with a letter (e.g. {{this.foo}}).
- If you meant the current context, write {{this}} explicitly rather than an empty path.
- Re-run or fix the preprocessor/codemod that produced the empty path and inspect its input.
Example fix
// before
{{}}
// after
{{this.title}} Defensive patterns
Strategy: validation
Validate before calling
// validate plain paths have a letter head before compiling
function assertValidPathHeads(template) {
const exprs = template.match(/{{([^}]*)}}/g) || [];
for (const e of exprs) {
const inner = e.slice(2, -2).trim();
if (inner && !/^[a-zA-Z@("']/.test(inner)) throw new Error(`Expression must start with a-z or A-Z: ${e}`);
}
}
assertValidPathHeads(template); Prevention
- Start every path with an identifier beginning with a letter
- Use {{this}} explicitly for current-context references
- Review codemod output for empty expressions like {{ }}
- Keep a syntax check (precompile) in your build so errors surface early
When it happens
Trigger: Compiling a template with a PathExpression whose parts list is empty/undefined after stripping data/source markers — e.g. a path expression that normalizes to an empty string reaching the visitor's else branch, where parts.shift() returns undefined.
Common situations: Malformed output from template preprocessors/codemods that drop the identifier; hand-edited templates leaving an empty expression like {{ }} that survives earlier validation; macros building paths programmatically with an empty head.
Related errors
- Changing context using "../" is not supported in Glimmer
- Mixing '.' and '/' in paths is not supported in Glimmer; use
- '.' is not a supported path in Glimmer; check for a path wit
- Attempted to parse a path expression, but it was not valid.
- ${node.path.type} "${node.path.type === 'StringLiteral' ? no
AI-assisted analysis of emberjs/ember.js@26f97246a8 (2026-09-01).
Data as JSON: /api/errors/b56c0ffda589a3d2.
Report an issue: GitHub.