{"record":{"id":"f4929db8a26292d8","repo":"emberjs/ember.js","slug":"component-has-both-else-and-inverse-block","errorCode":null,"errorMessage":"Component has both <:else> and <:inverse> block. <:inverse> is an alias for <:else>","messagePattern":"Component has both <:else> and <:inverse> block\\. <:inverse> is an alias for <:else>","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/@glimmer/syntax/lib/v2/normalize.ts","lineNumber":1036,"sourceCode":"      }\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\n      return this.namedBlocks;\n    } else {\n      return [\n        this.block.builder.namedBlock(\n          SourceSlice.synthetic('default'),\n          this.block.builder.block(table, this.nonBlockChildren, this.loc),\n          this.loc\n        ),\n      ];\n    }","sourceCodeStart":1018,"sourceCodeEnd":1054,"githubUrl":"https://github.com/emberjs/ember.js/blob/26f97246a8bf2e28edf26ac3093da2e86c04ffc5/packages/@glimmer/syntax/lib/v2/normalize.ts#L1018-L1054","documentation":"<:else> and <:inverse> are the same block: <:inverse> is an alias for <:else> (used for the false/else branch of conditionals). Passing both would be contradictory, so the normalizer rejects the invocation when both names appear in the seen set.","triggerScenarios":"Compiling an invocation that includes both blocks, e.g. <If @cond><:inverse>a</:inverse><:else>b</:else></If> — the dedup loop's alias check (name==='inverse' && seenNames.has('else') or vice versa) throws.","commonSituations":"Incremental migration where one author wrote <:else> and another added <:inverse> (or vice versa), or confusion about which alias spelling the component supports.","solutions":["Keep only <:else> (the canonical name) and delete the <:inverse> block","Or keep <:inverse> and delete <:else>, matching the component's documented convention","Merge the content of both blocks into the single retained block if both bodies were intended"],"exampleFix":"// before\n<Toggle>\n  <:inverse>Off</:inverse>\n  <:else>Disabled</:else>\n</Toggle>\n// after\n<Toggle>\n  <:else>\n    Off\n    Disabled\n  </:else>\n</Toggle>","handlingStrategy":"validation","validationCode":"function hasElseAndInverse(src) {\n  return /<:else>/.test(src) && /<:inverse>/.test(src);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pick one convention (usually <:else>) per codebase and document it","Search for `<:inverse>` when onboarding components that use `<:else>`","Treat them as aliases in code review checklists"],"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"}