handlebars-lang/handlebars.js · error · Exception

#unless requires exactly one argument

Error message

#unless requires exactly one argument

What it means

Handlebars' #unless helper is the inverse of #if and likewise requires exactly one conditional argument plus the options object. The error is thrown at render time when #unless is given zero or multiple positional arguments, before delegating to the 'if' helper with swapped fn/inverse blocks.

Source

Thrown at lib/handlebars/helpers/if.js:25

      throw new Exception('#if requires exactly one argument');
    }
    if (isFunction(conditional)) {
      conditional = conditional.call(this);
    }

    // Default behavior is to render the positive path if the value is truthy and not empty.
    // The `includeZero` option may be set to treat the conditional as purely not empty based on the
    // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative.
    if ((!options.hash.includeZero && !conditional) || isEmpty(conditional)) {
      return options.inverse(this);
    } else {
      return options.fn(this);
    }
  });

  instance.registerHelper('unless', function (conditional, options) {
    if (arguments.length != 2) {
      throw new Exception('#unless requires exactly one argument');
    }
    return instance.helpers['if'].call(this, conditional, {
      fn: options.inverse,
      inverse: options.fn,
      hash: options.hash,
    });
  });
}

View on GitHub (pinned to 13a7a67991)

Solutions

  1. Use exactly one argument: {{#unless value}}...{{/unless}}; remove extra positionals or convert them to hash pairs ({{#unless value key=val}}).
  2. Add the missing conditional if #unless was left bare.
  3. For compound conditions, wrap in a subexpression helper: {{#unless (or a b)}}.
  4. When invoking programmatically, pass options: unless(value, {fn, inverse, hash}).

Example fix

// before
{{#unless}}...{{/unless}}
// after
{{#unless user.isBlocked}}...{{/unless}}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-render validation: #unless must take exactly one positional argument
const bad = /\{\{#unless\s*(\}|[^}]+\s[^}\s]+\s+[^}\s]+\s*\})/.test(source);
if (bad) throw new Error('#unless must have exactly one positional argument');

Type guard

function hasExactlyOneArg(conditional, options) {
  return arguments.length === 2 && options && typeof options === 'object';
}

Try / catch

try {
  return template(data);
} catch (e) {
  if (e.message.includes('#unless requires exactly one argument')) {
    console.error('Template #unless has zero or multiple args; fix the template expression');
  }
  throw e;
}

Prevention

When it happens

Trigger: {{#unless}} with no argument; {{#unless a b}} with two positionals; calling instance.helpers.unless(value) directly without options; template assembly/parse quirks merging tokens so extra args end up on #unless.

Common situations: Copy-pasted templates where an argument was accidentally deleted or duplicated; upgrading or auto-formatting templates that mangled the mustache expression; direct helper invocation in tests missing the options object.

Related errors


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