emberjs/ember.js · error

You used ${variable}.${tail.join('.')} as a tag name, but ${

Error message

You used ${variable}.${tail.join('.')} as a tag name, but ${variable} is not in scope

What it means

A tag name containing a dot (`<foo.bar>`) implies a component invocation scoped through `foo`. When `foo` is not in scope (and there is a non-empty tail), the compiler throws this syntax error — dotted element names are not valid HTML.

Source

Thrown at packages/@glimmer/syntax/lib/v2/normalize.ts:853

        ? { result: ASTv2.STRICT_RESOLUTION }
        : this.ctx.resolutionFor(path, ComponentSyntaxContext);

      if (resolution.result === 'error') {
        throw generateSyntaxError(
          `You attempted to invoke a path (\`<${resolution.path}>\`) but ${resolution.head} was not in scope`,
          loc
        );
      }

      return new ExpressionNormalizer(this.ctx).normalize(path, resolution.result);
    } else {
      this.ctx.table.allocateFree(variable, ASTv2.STRICT_RESOLUTION);
    }

    // If the tag name wasn't a valid component but contained a `.`, it's
    // a syntax error.
    if (tail.length > 0) {
      throw generateSyntaxError(
        `You used ${variable}.${tail.join('.')} as a tag name, but ${variable} is not in scope`,
        loc
      );
    }

    return 'ElementHead';
  }

  private get expr(): ExpressionNormalizer {
    return new ExpressionNormalizer(this.ctx);
  }
}

class Children {
  readonly namedBlocks: ASTv2.NamedBlock[];
  readonly hasSemanticContent: boolean;
  readonly nonBlockChildren: ASTv2.ContentNode[];

View on GitHub (pinned to 26f97246a8)

Solutions

  1. Bind the head in scope: import the component or define `variable` via a block param / `let` / `@arg`.
  2. If you wanted an HTML element, replace the dotted name with a valid lowercase element tag.
  3. If it is a nested component, import it directly under its own name.

Example fix

// before
<cards.header @title="Hi" />

// after
import CardsHeader from './cards/header';
<CardsHeader @title="Hi" />
Defensive patterns

Strategy: validation

Validate before calling

// Reject dotted tag names whose head is not a known binding.
function validateTag(tag, scope) {
  const [head, ...tail] = tag.split('.');
  if (tail.length && !scope.has(head)) {
    throw new Error(`Tag ${tag}: '${head}' is not in scope`);
  }
}

Prevention

When it happens

Trigger: Compiling a template with a dotted tag name like `<my.thing>` or `<nested.Component>` where the part before the first dot is not a scoped local/import (loose mode resolution failed to find `variable`).

Common situations: Migrating from curly/loose conventions where dotted names resolved contextually; typos in component paths; expecting a helper/namespace-style element name to work as a tag.

Related errors


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