emberjs/ember.js · error

Component had two named blocks with the same name, `<:${name

Error message

Component had two named blocks with the same name, `<:${name}>`. Only one block with a given name may be passed

What it means

Each named block passed to a component must be unique. The normalizer keeps a Set of seen block names while iterating this.namedBlocks; encountering a duplicate name means the component would receive two blocks under one key, which is undefined semantics, so it throws.

Source

Thrown at packages/@glimmer/syntax/lib/v2/normalize.ts:1026

        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;

        if (seenNames.has(name)) {
          throw generateSyntaxError(
            `Component had two named blocks with the same name, \`<:${name}>\`. Only one block with a given name may be passed`,
            this.loc
          );
        }

        if (
          (name === 'inverse' && seenNames.has('else')) ||
          (name === 'else' && seenNames.has('inverse'))
        ) {
          throw generateSyntaxError(
            `Component has both <:else> and <:inverse> block. <:inverse> is an alias for <:else>`,
            this.loc
          );
        }

        seenNames.add(name);
      }

View on GitHub (pinned to 26f97246a8)

Solutions

  1. Rename one of the duplicate blocks to a distinct name
  2. Merge the duplicate blocks' content into a single named block, using {{#each}} inside for repetition
  3. If repeated sections are needed, invoke the component multiple times or restructure with a child component

Example fix

// before
<Tabs>
  <:tab>One</:tab>
  <:tab>Two</:tab>
</Tabs>
// after
<Tabs>
  <:tab>
    {{#each tabs as |t|}}{{t}}{{/each}}
  </:tab>
</Tabs>
Defensive patterns

Strategy: validation

Validate before calling

function findDuplicateNamedBlocks(src) {
  const names = [...src.matchAll(/<:(\w+)>/g)].map(m => m[1]);
  return names.filter((n, i) => names.indexOf(n) !== i);
}

Prevention

When it happens

Trigger: Compiling an invocation with two blocks of the same name, e.g. <Tabs><:tab>a</:tab><:tab>b</:tab></Tabs> — assertComponent's dedup loop throws when seenNames.has(name) is true.

Common situations: Generating templates programmatically (loops that emit <:item> per entry), copy-pasting a block and forgetting to rename it, or intending per-element blocks that should instead be one block with {{#each}} inside.

Related errors


AI-assisted analysis of emberjs/ember.js@26f97246a8 (2026-09-01). Data as JSON: /api/errors/096f92e9030c081d. Report an issue: GitHub.