emberjs/ember.js · error
Attempted to invoke a component that was not in scope in a s
Error message
Attempted to invoke a component that was not in scope in a strict mode template, \`<${variable}>\`. If you wanted to create an element with that name, convert it to lowercase - \`<${variable.toLowerCase()}>\` What it means
In strict-mode templates, an uppercase-first tag name is treated as a component invocation, so it must be bound in scope (imported component, local, or `@arg`). When it is not, the compiler throws instead of silently rendering an unknown element. Lowercase names are always treated as HTML elements.
Source
Thrown at packages/@glimmer/syntax/lib/v2/normalize.ts:806
* 2. If the variable is `this`, return a `ThisHead`
* 3. If the variable is in the current scope:
* a. If the scope is the root scope, then return a Free `LocalVarHead`
* b. Else, return a standard `LocalVarHead`
* 4. If the tag name is a path and the variable is not in the current scope, Syntax Error
* 5. If the variable is uppercase return a FreeVar(ResolveAsComponentHead)
* 6. Otherwise, return `'ElementHead'`
*/
private classifyTag(
variable: string,
tail: string[],
loc: SourceSpan
): ASTv2.ExpressionNode | 'ElementHead' {
let uppercase = isUpperCase(variable);
let inScope = variable[0] === '@' || variable === 'this' || this.ctx.hasBinding(variable);
if (this.ctx.strict && !inScope) {
if (uppercase) {
throw generateSyntaxError(
`Attempted to invoke a component that was not in scope in a strict mode template, \`<${variable}>\`. If you wanted to create an element with that name, convert it to lowercase - \`<${variable.toLowerCase()}>\``,
loc
);
}
// In strict mode, values are always elements unless they are in scope
return 'ElementHead';
}
// Since the parser handed us the HTML element name as a string, we need
// to convert it into an ASTv1 path so it can be processed using the
// expression normalizer.
let isComponent = inScope || uppercase;
let variableLoc = loc.sliceStartChars({ skipStart: 1, chars: variable.length });
let tailLength = tail.reduce((accum, part) => accum + 1 + part.length, 0);
let pathEnd = variableLoc.getEnd().move(tailLength);View on GitHub (pinned to 26f97246a8)
Solutions
- Import/define the component in scope: `import SomeComponent from '...';` before using `<SomeComponent />`.
- If you actually wanted a plain HTML element, lowercase the tag name, e.g. `<my-widget>`.
- Check the component name spelling/casing matches the in-scope binding.
Example fix
// before (strict mode)
<ProfileCard @user={{this.user}} />
// after
import ProfileCard from './profile-card';
<template><ProfileCard @user={{this.user}} /></template> Defensive patterns
Strategy: validation
Validate before calling
// Uppercase tags must be imported in strict-mode templates.
function componentTagInScope(tagName, imports /* Set<string> */) {
return !/^[A-Z]/.test(tagName) || imports.has(tagName);
} Prevention
- Import every component used in a `<template>` block at the top of the file.
- Keep component tags PascalCase and HTML tags lowercase to avoid ambiguity.
- Run template linting (ember-template-lint) to catch unresolved component tags.
When it happens
Trigger: Compiling a strict-mode template with `<SomeComponent />` where `SomeComponent` was not imported/defined in the template's scope.
Common situations: Upgrading to Ember strict-mode templates or `<template>` blocks and forgetting the import; renaming a component file so the import no longer matches; copying loose-mode templates into strict mode.
Related errors
- You attempted to pass a path as argument (\`${arg.name}={{${
- You attempted to invoke a path (\`<${resolution.path}>\`) bu
- Attempted to resolve `${name}`, which was expected to be a c
- Attempted to resolve a dynamic component with a string defin
- Attempted to resolve `${value}`, which was expected to be a
AI-assisted analysis of emberjs/ember.js@26f97246a8 (2026-09-01).
Data as JSON: /api/errors/461d152564597b42.
Report an issue: GitHub.