emberjs/ember.js · error · Exception

Unexpected inverse block on decorator

Error message

Unexpected inverse block on decorator

What it means

Decorators are metadata-only Handlebars nodes and cannot have an inverse ({{else}}) branch. When prepareBlock builds a decorator block and finds an inverse/else program attached, it throws because the construct is meaningless in Handlebars semantics.

Source

Thrown at packages/@handlebars/parser/lib/helpers.js:151

    closeStrip: {},
    loc: locInfo,
  };
}

export function prepareBlock(openBlock, program, inverseAndProgram, close, inverted, locInfo) {
  if (close && close.path) {
    validateClose(openBlock, close);
  }

  let decorator = /\*/.test(openBlock.open);

  program.blockParams = openBlock.blockParams;

  let inverse, inverseStrip;

  if (inverseAndProgram) {
    if (decorator) {
      throw new Exception('Unexpected inverse block on decorator', inverseAndProgram);
    }

    if (inverseAndProgram.chain) {
      inverseAndProgram.program.body[0].closeStrip = close.strip;
    }

    inverseStrip = inverseAndProgram.strip;
    inverse = inverseAndProgram.program;
  }

  if (inverted) {
    inverted = inverse;
    inverse = program;
    program = inverted;
  }

  return {
    type: decorator ? 'DecoratorBlock' : 'BlockStatement',

View on GitHub (pinned to 26f97246a8)

Solutions

  1. Remove the {{else}} branch from the decorator block
  2. Convert the construct to a regular block helper if you need inverse behavior
  3. Review template codegen/transform steps that wrap decorators in block syntax

Example fix

// before
{{#my-decorator}}
  main
{{else}}
  fallback
{{/my-decorator}}
// after
{{my-decorator}}
{{#if fallbackNeeded}}fallback{{/if}}
Defensive patterns

Strategy: validation

Validate before calling

// reject decorator blocks with else before parse
if (/{{\s*[#~][^}]*}}[\s\S]*{{\s*else/.test(src)) reviewTemplate(src);

Try / catch

try { parse(src); } catch (e) { if (/inverse block on decorator/.test(e.message)) { stripElseBranch(src); } throw e; }

Prevention

When it happens

Trigger: A template attaches an {{else}} to a decorator, e.g. {{#my-decorator}}...{{else}}...{{/my-decorator}} where my-decorator was parsed as a decorator (double-curlies with ~ or decorator registration context).

Common situations: Confusing decorators with block helpers; copy-pasted block syntax around a decorator; generated templates emitted with else branches for decorator nodes.

Related errors


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