emberjs/ember.js · error · Exception

${open.path.original} doesn't match ${close}

Error message

${open.path.original} doesn't match ${close}

What it means

The Handlebars parser validates that a closing block/partial-block tag matches the tag that opened it (e.g. {{#if}} ... {{/unless}}). When the open and close path names differ, validateClose throws with both names so you can find the mismatch in the template.

Source

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

import Exception from './exception.js';

function validateClose(open, close) {
  close = close.path ? close.path.original : close;

  if (open.path.original !== close) {
    let errorNode = { loc: open.path.loc };

    throw new Exception(open.path.original + " doesn't match " + close, errorNode);
  }
}

export function SourceLocation(source, locInfo) {
  this.source = source;
  this.start = {
    line: locInfo.first_line,
    column: locInfo.first_column,
  };
  this.end = {
    line: locInfo.last_line,
    column: locInfo.last_column,
  };
}

export function id(token) {
  if (/^\[.*\]$/.test(token)) {
    return token.substring(1, token.length - 1);

View on GitHub (pinned to 26f97246a8)

Solutions

  1. Make the close tag exactly match the open tag: {{#if x}} ... {{/if}}
  2. Check nesting order — inner blocks must close before outer ones
  3. Use an editor with Handlebars syntax highlighting/bracket matching to locate the mismatch
  4. If the name is legitimately different, restructure to separate sibling blocks

Example fix

// before
{{#each items}}
  {{name}}
{{/with}}
// after
{{#each items}}
  {{name}}
{{/each}}
Defensive patterns

Strategy: validation

Validate before calling

// pre-parse template lint to catch mismatches
const opens = [...template.matchAll(/{{#(\w+)/g)].map(m => m[1]);
const closes = [...template.matchAll(/{{\/(\w+)/g)].map(m => m[1]);
const matches = opens.length === closes.length && opens.slice().sort().join() === closes.slice().sort().join();

Try / catch

try { template = parse(src); } catch (e) { if (/doesn't match/.test(e.message)) { reportSyntaxError(src, e.loc, e.message); } throw e; }

Prevention

When it happens

Trigger: A template contains mismatched block tags: opening {{#foo}} and closing {{/bar}}, or closing {{#each}} with {{/with}}, including nested blocks closed in the wrong order.

Common situations: Hand-edited templates; copy/paste leaving a stale close tag; renamed a helper in the open tag but not the close; mismatched indentation hiding the real pairing.

Related errors


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