handlebars-lang/handlebars.js · error · Exception

"${name}" not defined in ${obj}

Error message

"${name}" not defined in ${obj}

What it means

In strict mode (compile with { strict: true }), the template's strict() helper throws when a referenced identifier is null/undefined or missing on its parent object, instead of rendering empty. This surfaces missing data at render time. The loc option points at the offending template location.

Source

Thrown at lib/handlebars/runtime.js:113

          lines[i] = options.indent + lines[i];
        }
        result = lines.join('\n');
      }
      return result;
    } else {
      throw new Exception(
        'The partial ' +
          options.name +
          ' could not be compiled when running in runtime-only mode'
      );
    }
  }

  // Just add water
  let container = {
    strict: function (obj, name, loc) {
      if (obj == null || !(name in Object(obj))) {
        throw new Exception('"' + name + '" not defined in ' + obj, {
          loc: loc,
        });
      }
      return container.lookupProperty(obj, name);
    },
    strictLookup: function (depths, name, loc) {
      const result = container.lookup(depths, name);
      return result !== undefined
        ? result
        : container.strict(undefined, name, loc);
    },
    lookupProperty: function (parent, propertyName) {
      if (Utils.isMap(parent)) {
        return parent.get(propertyName);
      }

      let result = parent[propertyName];
      if (result == null) {

View on GitHub (pinned to 13a7a67991)

Solutions

  1. Provide all referenced fields in the context before rendering
  2. Use {{#if}} or the default value syntax ({{missing}}{{else}}fallback) or compile without strict:true
  3. Guard with lookup helpers like {{lookup obj 'name'}} or the '?:' inline-if for optional fields

Example fix

// before (throws when user.name missing)
const t = Handlebars.compile('{{user.name}}', { strict: true });
t({});

// after
const t = Handlebars.compile('{{#if user.name}}{{user.name}}{{/if}}', { strict: true });
t({}); // renders '' instead of throwing
Defensive patterns

Strategy: try-catch

Validate before calling

function hasRequiredFields(ctx, keys) {
  return keys.every(k => k.split('.').reduce((o, p) => (o == null ? undefined : o[p]), ctx) != null);
}
// before render: hasRequiredFields(data, ['user.name'])

Type guard

function propDefined(obj, key) {
  return obj != null && key in Object(obj);
}

Try / catch

try {
  return template(data);
} catch (e) {
  if (/" not defined in /.test(e.message)) {
    // log e.loc, fix data or relax strict mode
  } else throw e;
}

Prevention

When it happens

Trigger: Rendering a strict-mode compiled template with data missing a referenced key, e.g. {{user.name}} where user is undefined or name is not a property of user.

Common situations: API responses missing fields; renamed JSON keys; tests rendering templates against fixtures that omit fields; turning strict:true on to catch typos and immediately hitting partial data.

Related errors


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