angular/components · error · SchematicsException

Cannot determine child element indentation because the speci

Error message

Cannot determine child element indentation because the specified Parse5 element does not have any source code location metadata.

What it means

getChildElementIndentation in src/cdk/schematics/utils/parse5-element.ts measures the column of a child element to compute indentation when inserting markup into HTML. Parse5 only provides sourceCodeLocation metadata when the document is parsed with location info enabled. If neither the child element nor the given element carries sourceCodeLocation, the function cannot compute indentation and throws this SchematicsException.

Source

Thrown at src/cdk/schematics/utils/parse5-element.ts:22

 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.dev/license
 */

import {SchematicsException} from '@angular-devkit/schematics';
import {DefaultTreeAdapterMap} from 'parse5';

// At the time of writing `parse5` doesn't expose the node interfaces directly, even though
// they're used as return types, but We can still access them through `DefaultTreeAdapterMap`.
export type Element = DefaultTreeAdapterMap['element'];
export type ChildNode = DefaultTreeAdapterMap['childNode'];

/** Determines the indentation of child elements for the given Parse5 element. */
export function getChildElementIndentation(element: Element) {
  const childElement = element.childNodes.find(node => (node as Element).tagName) as Element | null;

  if ((childElement && !childElement.sourceCodeLocation) || !element.sourceCodeLocation) {
    throw new SchematicsException(
      'Cannot determine child element indentation because the ' +
        'specified Parse5 element does not have any source code location metadata.',
    );
  }

  const startColumns = childElement
    ? // In case there are child elements inside of the element, we assume that their
      // indentation is also applicable for other child elements.
      childElement.sourceCodeLocation!.startCol
    : // In case there is no child element, we just assume that child elements should be indented
      // by two spaces.
      element.sourceCodeLocation!.startCol + 2;

  // Since Parse5 does not set the `startCol` properties as zero-based, we need to subtract
  // one column in order to have a proper zero-based offset for the indentation.
  return startColumns - 1;
}

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Parse the HTML with location info enabled (default html.parse / parse5 with sourceCodeLocationInfo: true) before passing elements to getChildElementIndentation.
  2. Pass elements obtained directly from a freshly parsed document, not programmatically created or deeply cloned nodes.
  3. If you control the caller, fall back to a default indentation (e.g. 2 or 4 spaces) when sourceCodeLocation is unavailable instead of calling the utility.
  4. Avoid round-tripping the HTML through serialize/parse cycles before indentation computation, which can strip location metadata.

Example fix

// before
const html = parse5.parse(fs.readFileSync('index.html', 'utf8'), { treeAdapter: customAdapter });
// after
const html = parse5.parse(fs.readFileSync('index.html', 'utf8'), { sourceCodeLocationInfo: true });
Defensive patterns

Strategy: type-guard

Validate before calling

const doc = parse5.parse(html, { sourceCodeLocationInfo: true });
if (!doc.sourceCodeLocation) throw new Error('Parse5 tree lacks source code locations; re-parse with sourceCodeLocationInfo: true');

Type guard

function hasSourceCodeLocation(el: parse5.Element): el is parse5.Element & { sourceCodeLocation: parse5.ElementLocation } {
  return !!el.sourceCodeLocation && el.childNodes.some(n => 'tagName' in n && !!(n as parse5.Element).sourceCodeLocation);
}

Try / catch

try {
  const indent = getChildElementIndentation(head);
} catch (e) {
  if (String(e.message).includes('source code location metadata')) {
    const indent = '  '; // fallback to 2-space indentation
  } else throw e;
}

Prevention

When it happens

Trigger: A schematic (e.g. addHtmlElementToBody/head flows that compute indentation via indentationOffset) parses index.html whose resulting Parse5 Element has no sourceCodeLocation — typically because the tree was built without location info or produced programmatically rather than parsed from source text.

Common situations: Mostly hit by developers writing or extending schematics that reuse these utilities: constructing Parse5 nodes manually, parsing with treeAdapter/parsing options that omit location info, or feeding already-transformed (serialized/re-parsed) HTML through the utility.

Related errors


AI-assisted analysis of angular/components@0411926e7d (2026-08-31). Data as JSON: /api/errors/69777c4ce8564589. Report an issue: GitHub.