{"record":{"id":"096f92e9030c081d","repo":"emberjs/ember.js","slug":"component-had-two-named-blocks-with-the-same-name","errorCode":null,"errorMessage":"Component had two named blocks with the same name, `<:${name}>`. Only one block with a given name may be passed","messagePattern":"Component had two named blocks with the same name, `<:(.+?)>`\\. Only one block with a given name may be passed","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/@glimmer/syntax/lib/v2/normalize.ts","lineNumber":1026,"sourceCode":"        this.loc\n      );\n    }\n\n    if (isPresentArray(this.namedBlocks)) {\n      if (hasBlockParams) {\n        throw generateSyntaxError(\n          `Unexpected block params list on <${name}> component invocation: when passing named blocks, the invocation tag cannot take block params`,\n          this.loc\n        );\n      }\n\n      let seenNames = new Set<string>();\n\n      for (let block of this.namedBlocks) {\n        let name = block.name.chars;\n\n        if (seenNames.has(name)) {\n          throw generateSyntaxError(\n            `Component had two named blocks with the same name, \\`<:${name}>\\`. Only one block with a given name may be passed`,\n            this.loc\n          );\n        }\n\n        if (\n          (name === 'inverse' && seenNames.has('else')) ||\n          (name === 'else' && seenNames.has('inverse'))\n        ) {\n          throw generateSyntaxError(\n            `Component has both <:else> and <:inverse> block. <:inverse> is an alias for <:else>`,\n            this.loc\n          );\n        }\n\n        seenNames.add(name);\n      }\n","sourceCodeStart":1008,"sourceCodeEnd":1044,"githubUrl":"https://github.com/emberjs/ember.js/blob/26f97246a8bf2e28edf26ac3093da2e86c04ffc5/packages/@glimmer/syntax/lib/v2/normalize.ts#L1008-L1044","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rename one of the duplicate blocks to a distinct name","Merge the duplicate blocks' content into a single named block, using {{#each}} inside for repetition","If repeated sections are needed, invoke the component multiple times or restructure with a child component"],"exampleFix":"// before\n<Tabs>\n  <:tab>One</:tab>\n  <:tab>Two</:tab>\n</Tabs>\n// after\n<Tabs>\n  <:tab>\n    {{#each tabs as |t|}}{{t}}{{/each}}\n  </:tab>\n</Tabs>","handlingStrategy":"validation","validationCode":"function findDuplicateNamedBlocks(src) {\n  const names = [...src.matchAll(/<:(\\w+)>/g)].map(m => m[1]);\n  return names.filter((n, i) => names.indexOf(n) !== i);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Unique block names per invocation; use {{#each}} inside one block for repetition","Careful with template generation code that emits blocks in loops","Add a lint rule or code-review checklist for duplicate `<:name>`"],"tags":["glimmer","handlebars","named-blocks","template-syntax"],"backgroundTag":"duplicate-named-block","analyzedSha":"26f97246a8bf2e28edf26ac3093da2e86c04ffc5","analyzedAt":"2026-09-01T05:01:28.182Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}