emberjs/ember.js · error · Exception

Unexpected node type "${value.type}" found when accepting ${

Error message

Unexpected node type "${value.type}" found when accepting ${name} on ${node.type}

What it means

The visitor's acceptKey sanity check (active when the visitor is mutating) verifies that any node produced while traversing a key has a registered visitor handler. If a child value has an unknown node type, it throws rather than silently corrupting the AST during mutation passes.

Source

Thrown at packages/@handlebars/parser/lib/visitor.js:18

import Exception from './exception.js';

function Visitor() {
  this.parents = [];
}

Visitor.prototype = {
  constructor: Visitor,
  mutating: false,

  // Visits a given value. If mutating, will replace the value if necessary.
  acceptKey: function (node, name) {
    let value = this.accept(node[name]);
    if (this.mutating) {
      // Hacky sanity check: This may have a few false positives for type for the helper
      // methods but will generally do the right thing without a lot of overhead.
      if (value && !Visitor.prototype[value.type]) {
        throw new Exception(
          'Unexpected node type "' +
            value.type +
            '" found when accepting ' +
            name +
            ' on ' +
            node.type
        );
      }
      node[name] = value;
    }
  },

  // Performs an accept operation with added sanity check to ensure
  // required keys are not removed.
  acceptRequired: function (node, name) {
    this.acceptKey(node, name);

    if (!node[name]) {

View on GitHub (pinned to 26f97246a8)

Solutions

  1. Fix the transform to only insert nodes with valid, registered types (e.g. 'MustacheStatement', 'PathExpression')
  2. Check the type string for typos on hand-constructed nodes
  3. Update visitor/transform packages so versions match the parser AST spec
  4. Temporarily run non-mutating to inspect the AST and find the offending node

Example fix

// before
node.params.push({ type: 'mustache', original: 'x' });
// after
node.params.push({ type: 'SubExpression', path: { type: 'PathExpression', original: 'x', data: false, depth: 0, parts: ['x'], loc: null }, params: [], hash: { type: 'Hash', pairs: [], loc: null }, loc: null });
Defensive patterns

Strategy: validation

Validate before calling

const VALID = new Set(['Program','MustacheStatement','BlockStatement','PartialBlockStatement','PartialStatement','CommentStatement','MustacheCommentStatement','DecoratorBlock','Decorator','ElementNode','AttrNode','TextNode','ConcatStatement','SubExpression','PathExpression','Hash','HashPair','BooleanLiteral','NumberLiteral','StringLiteral','UndefinedLiteral','NullLiteral','Block']);
function validNode(n) { return n == null || VALID.has(n.type); }

Type guard

function isAstNode(v) { return v != null && typeof v.type === 'string' && Visitor.prototype[v.type] !== undefined; }

Try / catch

try { visitor.visit(ast); } catch (e) { if (/Unexpected node type/.test(e.message)) { dumpAstAtError(ast, e.message); } throw e; }

Prevention

When it happens

Trigger: A mutating Visitor pass (whitespace control, transforms, ember-template-recast-style edits) sets a node key to a value whose .type has no Visitor.prototype handler, or hand-builds AST nodes with a typo'd type field.

Common situations: Custom AST transforms inserting malformed nodes; plugins/glint/codemods operating on templates; version mismatch where a new node type isn't handled by an older visitor.

Related errors


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