emberjs/ember.js · error
Unexpected named block nested in a normal block
Error message
Unexpected named block nested in a normal block
What it means
Named blocks cannot be nested inside an ordinary block — i.e. inside `{{#if}}`, `{{#each}}`, or any other normal `{{#...}}` block. BlockChildren.assertBlock throws when named blocks appear among a normal block's children.
Source
Thrown at packages/@glimmer/syntax/lib/v2/normalize.ts:913
(c): c is ASTv2.ContentNode => !(c instanceof ASTv2.NamedBlock)
);
}
}
class TemplateChildren extends Children {
assertTemplate(table: ProgramSymbolTable): ASTv2.Template {
if (isPresentArray(this.namedBlocks)) {
throw generateSyntaxError(`Unexpected named block at the top-level of a template`, this.loc);
}
return this.block.builder.template(table, this.nonBlockChildren, this.block.loc(this.loc));
}
}
class BlockChildren extends Children {
assertBlock(table: BlockSymbolTable): ASTv2.Block {
if (isPresentArray(this.namedBlocks)) {
throw generateSyntaxError(`Unexpected named block nested in a normal block`, this.loc);
}
return this.block.builder.block(table, this.nonBlockChildren, this.loc);
}
}
class ElementChildren extends Children {
constructor(
private el: BuildElement,
loc: SourceSpan,
children: (ASTv2.ContentNode | ASTv2.NamedBlock)[],
block: BlockContext
) {
super(loc, children, block);
}
assertNamedBlock(name: SourceSlice, table: BlockSymbolTable): ASTv2.NamedBlock {
if (this.el.base.selfClosing) {View on GitHub (pinned to 26f97246a8)
Solutions
- Move the named block to be a direct child of the element/component tag it belongs to.
- To make a named block conditional, put the condition inside the named block, not around it.
- Split into multiple invocations if different named block sets are needed per condition.
Example fix
// before
<Card>
{{#if this.showHeader}}
<:header>Hi</:header>
{{/if}}
</Card>
// after
<Card>
<:header>{{#if this.showHeader}}Hi{{/if}}</:header>
</Card> Defensive patterns
Strategy: validation
Validate before calling
// Named blocks must be direct children of a tag, not inside {{#blocks}}.
function assertNamedBlocksNotNested(children) {
for (const c of children) {
if (c.type === 'block' && c.children.some(x => x.type === 'named-block')) {
throw new Error('Named block nested inside a normal {{#block}}');
}
}
} Prevention
- Keep `<:name>` blocks at the top level of their element/component tag.
- Move conditionals inside named blocks instead of wrapping named blocks in `{{#if}}`.
- Use `{{yield to=...}}` with `has-block` checks for conditional sections.
When it happens
Trigger: Compiling a template where `<:name>...</:name>` appears inside e.g. `{{#if cond}} ... <:name> ... {{/if}}`.
Common situations: Conditionally wrapping named blocks with `{{#if}}`; accidentally placing a named block after another block's content but still inside its curlies; copy-paste refactors.
Related errors
- Unexpected named block at the top-level of a template
- <:${name.chars}/> is not a valid named block: named blocks c
- Unexpected named block inside <:${name.chars}> named block:
- named block <:${name.chars}> cannot have attributes, argumen
- You used ${variable}.${tail.join('.')} as a tag name, but ${
AI-assisted analysis of emberjs/ember.js@26f97246a8 (2026-09-01).
Data as JSON: /api/errors/25989cc84703df79.
Report an issue: GitHub.