emberjs/ember.js · error
Invalid block parameters syntax: block parameters must be pr
Error message
Invalid block parameters syntax: block parameters must be preceded by the `as` keyword
What it means
Glimmer's parser encountered an attribute-like token starting with a pipe character (e.g. `<Hello |foo|>`) that is not part of a valid block params form. Block parameters must be introduced with the `as` keyword (`<Hello as |foo|>`); a leading `|` without it is assumed to be a user mistake with block-params syntax, so the parser throws a syntax error instead of silently treating it as an attribute.
Source
Thrown at packages/@glimmer/syntax/lib/parser/tokenizer-event-handlers.ts:302
finishAttributeValue(): void {
this.finalizeTextPart();
let tag = this.currentTag;
let tokenizerPos = this.offset();
if (tag.type === 'EndTag') {
throw generateSyntaxError(
`Invalid end tag: closing tag must not have attributes`,
this.source.spanFor({ start: tag.start.toJSON(), end: tokenizerPos.toJSON() })
);
}
let { name, parts, start, isQuoted, isDynamic, valueSpan } = this.currentAttr;
// Just trying to be helpful with `<Hello |foo|>` rather than letting it through as an attribute
if (name.startsWith('|') && parts.length === 0 && !isQuoted && !isDynamic) {
throw generateSyntaxError(
'Invalid block parameters syntax: block parameters must be preceded by the `as` keyword',
start.until(start.move(name.length))
);
}
let value = this.assembleAttributeValue(parts, isQuoted, isDynamic, start.until(tokenizerPos));
value.loc = valueSpan.withEnd(tokenizerPos);
let attribute = b.attr({ name, value, loc: start.until(tokenizerPos) });
this.currentStartTag.attributes.push(attribute);
}
private parsePossibleBlockParams() {
// const enums that we can't use directly
const BEFORE_ATTRIBUTE_NAME = 'beforeAttributeName' as TokenizerState.beforeAttributeName;
const ATTRIBUTE_NAME = 'attributeName' as TokenizerState.attributeName;
const AFTER_ATTRIBUTE_NAME = 'afterAttributeName' as TokenizerState.afterAttributeName;View on GitHub (pinned to 26f97246a8)
Solutions
- Add the `as` keyword before the pipes: `<Hello as |foo|>`
- If you intended an attribute, rename it so it does not start with `|`
- Quote the value if a pipe character is genuinely part of an attribute value
Example fix
// before
<Hello |name|>Hi {{name}}</Hello>
// after
<Hello as |name|>Hi {{name}}</Hello> Defensive patterns
Strategy: validation
Validate before calling
// Pre-validate template tag opening forms: any `|` after a tag name must follow `as `
if (/<[^>\n]*\s\|/.test(tagOpen) && !/<[^>\n]*\bas\s\|/.test(tagOpen)) {
throw new Error('Block params must use `as |name|`');
} Prevention
- Always write `as |name|` with the `as` keyword before pipes
- Run templates through the glimmer precompiler in CI to catch syntax errors early
- Enable editor syntax highlighting/linting for handlebars/glimmer templates
When it happens
Trigger: In finishAttributeValue, when the current tag attribute name starts with '|', is unquoted, is not dynamic, and has zero parts — i.e. a template contains something like `<Component |param|>` without the preceding `as`.
Common situations: Typing `<Foo |bar|>` out of habit from Ruby-style blocks; copy-pasting older `<Foo |a b|>` syntax that predates the `as` requirement; forgetting `as` when converting a normal attribute into block params.
Related errors
- Invalid block parameters syntax: expecting at least one spac
- Invalid block parameters syntax: mustaches cannot be used in
- Invalid block parameters syntax: expecting the tag to be clo
- Invalid block parameters syntax: empty parameters list, expe
- Invalid block parameters syntax: incomplete parameters list,
AI-assisted analysis of emberjs/ember.js@26f97246a8 (2026-09-01).
Data as JSON: /api/errors/551093d1a38946b6.
Report an issue: GitHub.