emberjs/ember.js · error
Unexpected content inside <${name}> component invocation: wh
Error message
Unexpected content inside <${name}> component invocation: when using named blocks, the tag cannot contain other content What it means
When a component invocation uses named blocks (<:header>, <:body>, ...), the tag itself must contain nothing else. The normalizer tracks whether the tag had semantic content (text, elements, mustaches) besides the named blocks, and rejects the mix because there is no semantics for where such content would render.
Source
Thrown at packages/@glimmer/syntax/lib/v2/normalize.ts:1006
} else {
let printedNames = names.map((n) => `<:${n.chars}>`).join(', ');
throw generateSyntaxError(
`Unexpected named blocks inside <${name.chars}> HTML element (${printedNames})`,
this.loc
);
}
}
return this.el.simple(name, this.nonBlockChildren, this.loc);
}
assertComponent(
name: string,
table: BlockSymbolTable,
hasBlockParams: boolean
): PresentArray<ASTv2.NamedBlock> {
if (isPresentArray(this.namedBlocks) && this.hasSemanticContent) {
throw generateSyntaxError(
`Unexpected content inside <${name}> component invocation: when using named blocks, the tag cannot contain other content`,
this.loc
);
}
if (isPresentArray(this.namedBlocks)) {
if (hasBlockParams) {
throw generateSyntaxError(
`Unexpected block params list on <${name}> component invocation: when passing named blocks, the invocation tag cannot take block params`,
this.loc
);
}
let seenNames = new Set<string>();
for (let block of this.namedBlocks) {
let name = block.name.chars;
View on GitHub (pinned to 26f97246a8)
Solutions
- Move the non-block content into a named block (commonly <:default> or <:body>)
- Remove the extra content so the tag contains only named blocks
- Remove the named blocks and pass everything as default block content if blocks aren't needed
Example fix
// before <Card> <:header>Title</:header> Body text here </Card> // after <Card> <:header>Title</:header> <:body>Body text here</:body> </Card>
Defensive patterns
Strategy: validation
Validate before calling
function invocationHasMixedContent(src) {
const m = src.match(/<(\w+)[^>]*>([\s\S]*?)<\/\1>/);
if (!m) return false;
const body = m[2];
const hasBlocks = /<:\w+>/.test(body);
const other = body.replace(/<:\w+>[\s\S]*?<:\/\w+>/g, '').trim();
return hasBlocks && other.length > 0;
} Prevention
- Convention: a tag either has only named blocks, or only plain content — never both
- When adding a named block, wrap existing content in <:default> or <:body> in the same edit
- Review diffs that introduce `<:` in templates for leftover sibling content
When it happens
Trigger: Compiling an invocation like <MyCard><:header>h</:header>Some text</MyCard> or <Foo><:body>x</:body><p>y</p></Foo> — assertComponent fires when namedBlocks is present AND hasSemanticContent is true.
Common situations: Incrementally converting a normal component call to named blocks while leaving old content in the tag, or adding a named block to an existing invocation whose body already has content.
Related errors
- Invalid named block named detected, you may have created a n
- Unexpected named block <:foo> inside <${name.chars}> HTML el
- Unexpected named blocks inside <${name.chars}> HTML element
- Unexpected block params list on <${name}> component invocati
- Component had two named blocks with the same name, `<:${name
AI-assisted analysis of emberjs/ember.js@26f97246a8 (2026-09-01).
Data as JSON: /api/errors/9bee2b9984a78134.
Report an issue: GitHub.