emberjs/ember.js · error

Invalid block parameters syntax: modifiers cannot follow par

Error message

Invalid block parameters syntax: modifiers cannot follow parameters list

What it means

Glimmer's block-params lookahead parser (parsePossibleBlockParams) accepts `|a b|` after a tag name only if the tag is then closed. When a mustache (modifier, e.g. `{{action}}`) appears after the parameters list, the tokenizer's pendingError.mustache callback fires, because modifiers cannot follow a block-params list in Handlebars syntax.

Source

Thrown at packages/@glimmer/syntax/lib/parser/tokenizer-event-handlers.ts:505

          // slurp up anything else into the name, validate later
          state.name += next;
          this.tokenizer.consume();
        }
      },

      AfterEndPipe: (next: string) => {
        assert(state.state === 'AfterEndPipe', 'bug in block params parser');

        if (isSpace(next)) {
          this.tokenizer.consume();
        } else if (next === '') {
          // The HTML tokenizer ran out of characters, so we are either
          // encountering mustache or <EOF>, HBS side will attach the error
          // to the next span
          state = { state: 'Done' };
          this.pendingError = {
            mustache(loc: src.SourceSpan) {
              throw generateSyntaxError(
                `Invalid block parameters syntax: modifiers cannot follow parameters list`,
                loc
              );
            },
            eof(loc: src.SourceOffset) {
              throw generateSyntaxError(
                `Invalid block parameters syntax: expecting the tag to be closed with ">" or "/>" after parameters list`,
                as.start.until(loc)
              );
            },
          };
        } else if (next === '>' || next === '/') {
          // Don't consume, let the normal tokenizer code handle the next steps
          state = { state: 'Done' };
        } else {
          // Slurp up the next "token" for the error span
          state = {
            state: 'Error',

View on GitHub (pinned to 26f97246a8)

Solutions

  1. Remove the block params list from the element tag; block params belong on curly block form (`{{#foo as |a b|}}`)
  2. Remove the element modifier if block-params-like syntax was intentional elsewhere
  3. Wrap the content in a real block or component that supports `as |...|`

Example fix

// before
<div |a b| {{on "click" this.go}}>...</div>
// after
<div {{on "click" this.go}}>...</div>
Defensive patterns

Strategy: validation

Validate before calling

// crude guard before parsing
if (/^<[^>]*\|[^>]*\|[^>]*\{\{/m.test(template)) {
  throw new Error('Block params cannot be followed by a modifier mustache on the tag');
}

Try / catch

try { parse(template) } catch (e) { if (/modifiers cannot follow parameters list/.test(e.message)) { /* report template location / fallback */ } else throw e; }

Prevention

When it happens

Trigger: Parsing a template where a mustache/modifier follows a block params list on an element, e.g. `<div |a b| {{action}}>`; the mustache handler throws the pending error.

Common situations: Hand-written components mixing block params with element modifiers; refactoring `<div ... as |a b|>` style from block form onto the tag itself; misunderstanding that `as |x|` only applies in block form, not on element tags.

Related errors


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