emberjs/ember.js · error
In ${tag}, ${modifier} is not a valid modifier
Error message
In ${tag}, ${modifier} is not a valid modifier What it means
Element modifiers in Glimmer templates must be identifier paths (helpers like {{on "click" ...}} or {{action ...}}), never Handlebars literals. When a mustache used as an element modifier ({{...}} inside a tag) has a literal path, addElementModifier builds a synthetic tag snippet and throws a syntax error, since a literal cannot resolve to a modifier.
Source
Thrown at packages/@glimmer/syntax/lib/parser/handlebars-node-visitors.ts:670
: b.hash({
pairs: [],
loc: compiler.source.spanFor(end).collapse('end'),
});
return { path, params, hash };
}
function addElementModifier(
element: ParserNodeBuilder<StartTag>,
mustache: ASTv1.MustacheStatement
) {
const { path, params, hash, loc } = mustache;
if (isHBSLiteral(path)) {
const modifier = `{{${printLiteral(path)}}}`;
const tag = `<${element.name} ... ${modifier} ...`;
throw generateSyntaxError(`In ${tag}, ${modifier} is not a valid modifier`, mustache.loc);
}
const modifier = b.elementModifier({ path, params, hash, loc });
element.modifiers.push(modifier);
}
function repairBlock(
source: src.Source,
block: HBS.UpstreamBlockStatement,
fallbackStart: SourceSpan
): HBS.BlockStatement {
// Extend till the beginning of the block
if (!block.program.loc) {
const start = block.program.body.at(0);
const end = block.program.body.at(-1);
if (start && end) {
block.program.loc = {View on GitHub (pinned to 26f97246a8)
Solutions
- Use a real modifier helper path: <button {{on "click" this.save}}>Change</button> or <form {{action "submit" on="submit"}}> in classic Ember.
- Unquote the modifier name if it was accidentally quoted: {{"action" ...}} → {{action ...}}.
- Remove the stray literal from the tag if it was leftover text, and validate the template with ember-template-lint to catch it earlier.
Example fix
// before
<button {{"onclick"}}></button>
// after
<button {{on "click" this.handleClick}}>Save</button> Defensive patterns
Strategy: validation
Validate before calling
// reject literal mustaches used as element modifiers
function assertValidModifiers(template) {
const bad = template.match(/<[A-Za-z][^>]*{{\s*("[^"]*"|'[^']*'|\d+|true|false|null)\s*[^}]*}}[^>]*>/g);
if (bad) throw new Error(`Literal is not a valid modifier: ${bad.join(', ')}`);
}
assertValidModifiers(template); Prevention
- Use recognized modifier helpers like {{on "click" fn}} or {{action ...}} inside tags
- Never quote a modifier name inside the tag
- Prefer the modern {{on}} modifier with element modifiers over inline handlers
- Run ember-template-lint (rule: no-invalid-role / modifier checks) in CI
When it happens
Trigger: Writing a literal inside an element tag as if it were a modifier: <div {{"foo"}}></div>, <input {{42}} />, <button {{true}}></button>. Thrown in addElementModifier (called from MustacheStatement handling) when isHBSLiteral(path) is true.
Common situations: Typos where a modifier name was deleted or quoted by accident (<div {{"on" "click" ...}}); copy/paste mangling of the {{on ...}} / {{action ...}} syntax; template editors auto-quoting identifiers.
Related errors
- Changing context using "../" is not supported in Glimmer
- Mixing '.' and '/' in paths is not supported in Glimmer; use
- '.' is not a supported path in Glimmer; check for a path wit
- Attempted to parse a path expression, but it was not valid.
- Attempted to parse a path expression, but it was not valid.
AI-assisted analysis of emberjs/ember.js@26f97246a8 (2026-09-01).
Data as JSON: /api/errors/801ebb077d790996.
Report an issue: GitHub.