handlebars-lang/handlebars.js · error · Exception

Compile completed with content left on stack

Error message

Compile completed with content left on stack

What it means

An internal compiler sanity check: after generating code for the template, the JavaScriptCompiler expects all value stacks (stackSlot, inlineStack, compileStack) to be empty. Leftover entries mean codegen produced unbalanced push/pop sequences — typically a compiler bug or corrupted AST.

Source

Thrown at lib/handlebars/compiler/javascript-compiler.js:117

      firstLoc,
      i,
      l;

    for (i = 0, l = opcodes.length; i < l; i++) {
      opcode = opcodes[i];

      this.source.currentLocation = opcode.loc;
      firstLoc = firstLoc || opcode.loc;
      this[opcode.opcode].apply(this, opcode.args);
    }

    // Flush any trailing content that might be pending.
    this.source.currentLocation = firstLoc;
    this.pushSource('');

    /* v8 ignore next */
    if (this.stackSlot || this.inlineStack.length || this.compileStack.length) {
      throw new Exception('Compile completed with content left on stack');
    }

    if (!this.decorators.isEmpty()) {
      this.useDecorators = true;

      this.decorators.prepend([
        'var decorators = container.decorators, ',
        this.lookupPropertyFunctionVarDeclaration(),
        ';\n',
      ]);
      this.decorators.push('return fn;');

      if (asObject) {
        // eslint-disable-next-line no-new-func
        this.decorators = Function.apply(this, [
          'fn',
          'props',
          'container',

View on GitHub (pinned to 13a7a67991)

Solutions

  1. Upgrade Handlebars to the latest patch release — this is usually a fixed compiler bug.
  2. Remove custom compiler patches/subclasses overriding opcode emission.
  3. Reduce the template to a minimal repro and file an issue with the template and version.
  4. Avoid post-processing the AST before compile in ways that unbalance nodes.

Example fix

// before
const compiler = Handlebars.JavaScriptCompiler;
compiler.prototype.pushExtra = ...; // custom patch
// after
Use stock Handlebars compiler; upgrade version instead of patching.
Defensive patterns

Strategy: try-catch

Try / catch

try { return Handlebars.compile(src)(data); } catch (e) { if (/content left on stack/.test(e.message)) { reportCompilerBug(src, Handlebars.VERSION); } throw e; }

Prevention

When it happens

Trigger: Compiling a template where internal opcode emission leaves values unpopped; custom compiler patches/subclasses that emit extra opcodes; very old Handlebars versions with known codegen bugs.

Common situations: Monkey-patching the compiler or custom node visitors; encountering a Handlebars bug report — users usually hit this via unusual template constructs.

Related errors


AI-assisted analysis of handlebars-lang/handlebars.js@13a7a67991 (2026-09-02). Data as JSON: /api/errors/5ebbfd295f0b9c99. Report an issue: GitHub.