emberjs/ember.js · error
An unquoted attribute value must be a string or a mustache,
Error message
An unquoted attribute value must be a string or a mustache, preceded by whitespace or a '=' character, and followed by whitespace, a '>' character, or '/>'
What it means
assembleAttributeValue, when assembling an unquoted attribute value from concatenated parts (text/mustache), only allows a single part (or a lone `/`). If more than one part remains after simplification — e.g. an unquoted value mixing text and mustaches — the value is invalid for unquoted form and this error is thrown.
Source
Thrown at packages/@glimmer/syntax/lib/parser/tokenizer-event-handlers.ts:617
}
assembleAttributeValue(
parts: ASTv1.AttrPart[],
isQuoted: boolean,
isDynamic: boolean,
span: src.SourceSpan
): ASTv1.AttrValue {
if (isDynamic) {
if (isQuoted) {
return this.assembleConcatenatedValue(parts);
} else {
assertPresentArray(parts);
const [head, a] = parts;
if (a === undefined || (a.type === 'TextNode' && a.chars === '/')) {
return head;
} else {
throw generateSyntaxError(
`An unquoted attribute value must be a string or a mustache, ` +
`preceded by whitespace or a '=' character, and ` +
`followed by whitespace, a '>' character, or '/>'`,
span
);
}
}
} else if (isPresentArray(parts)) {
return parts[0];
} else {
return b.text({ chars: '', loc: span });
}
}
}
/**
ASTPlugins can make changes to the Glimmer template AST before
compilation begins.View on GitHub (pinned to 26f97246a8)
Solutions
- Quote the attribute value: `class="a{{x}}b"`
- Use a single mustache or single text node for unquoted values, e.g. `class={{x}}`
- Build the combined string in JS and pass one value instead
Example fix
// before
<div class=a{{x}}b>...</div>
// after
<div class="a{{x}}b">...</div> Defensive patterns
Strategy: validation
Validate before calling
// unquoted attr values with interpolation are invalid
if (/<\w+\s+[\w-]+=[^\s"'>{]*\{\{/m.test(template)) {
throw new Error('Quote attribute values containing mustaches');
} Try / catch
try { parse(template) } catch (e) { if (/unquoted attribute value/.test(e.message)) { /* auto-quote the attribute and reparse */ } else throw e; } Prevention
- Always quote dynamic attribute values
- Use single-mustache form `attr={{value}}` when unquoted
- Lint for unquoted attributes
When it happens
Trigger: Unquoted attribute value containing a mustache plus extra text or a trailing slash, e.g. `<div class="a{{x}}">` written as `<div class=a{{x}}b>` or `<div foo=bar/>`-style oddities.
Common situations: Writing dynamic attribute values without quotes; forgetting quotes after refactoring `<div class={{x}}>rest`; shell-style `/` at the end of an unquoted value.
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/2c925b7ad1e02e55.
Report an issue: GitHub.