hcengineering/platform · error · Error

descendants not found: ${_class}

Error message

descendants not found: ${_class}

What it means

Hierarchy.getDescendants returns the precomputed list of descendant classes for a registered classifier from the internal descendants map. The map is populated during hierarchy construction (updateDescendant). If the class was never added to the hierarchy, no descendant entry exists and this Error is thrown.

Source

Thrown at foundations/core/packages/core/src/hierarchy.ts:390

   */
  private isExtends<T extends Doc>(extendsOrImplements: Ref<Interface<Doc>>[], from: Ref<Interface<T>>): boolean {
    const result: Ref<Interface<Doc>>[] = []
    const toVisit = [...extendsOrImplements]
    while (toVisit.length > 0) {
      const ref = toVisit.shift() as Ref<Interface<Doc>>
      if (ref === from) {
        return true
      }
      addIf(result, ref)
      toVisit.push(...this.ancestorsOf(ref))
    }
    return false
  }

  getDescendants<T extends Obj>(_class: Ref<Class<T>>): Ref<Class<Obj>>[] {
    const data = this.descendants.get(_class)
    if (data === undefined) {
      throw new Error('descendants not found: ' + _class)
    }
    return data
  }

  private updateDescendant (_class: Ref<Classifier>, add = true): void {
    let hierarchy: Ref<Classifier>[] = []

    try {
      hierarchy = this.getAncestors(_class)
    } catch (err) {
      if (add) {
        throw err
      }
    }

    for (const cls of hierarchy) {
      const list = this.descendants.get(cls)
      if (list === undefined) {

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Ensure all model txes (including the class definition) have been applied via hierarchy.addedTx before querying descendants
  2. Verify the class ref belongs to an installed model package
  3. For optional classes, filter with hierarchy.findClass first or wrap in try/catch
  4. Check initialization order so descendants queries happen after hierarchy hydration

Example fix

// before
const sub = hierarchy.getDescendants(core.class.Doc)
// after
if (hierarchy.findClass(core.class.Doc) === undefined) {
  throw new Error('Hierarchy not initialized - model txes missing')
}
const sub = hierarchy.getDescendants(core.class.Doc)
Defensive patterns

Strategy: validation

Validate before calling

if (hierarchy.findClass(_class) === undefined) {
  throw new Error(`Hierarchy not initialized for ${String(_class)} - missing model tx`)
}
const descendants = hierarchy.getDescendants(_class)

Type guard

function hasDescendants(h: Hierarchy, c: Ref<Class<Obj>>): boolean {
  return h.findClass(c) !== undefined
}

Try / catch

let subtypes: Ref<Class<Obj>>[]
try {
  subtypes = hierarchy.getDescendants(_class)
} catch (err) {
  console.error(`Descendants unavailable for ${String(_class)}; hierarchy not hydrated`, err)
  throw err
}

Prevention

When it happens

Trigger: Calling getDescendants (directly or via classes, descendants, isClassIndexable, getFullTextIndexableAttributes) with a class ref whose hierarchy.addedTx was never processed; calling before initial model sync completes.

Common situations: Querying descendants during startup before the model transaction batch finishes; plugin model not installed; constructing a fresh Hierarchy in tests without replaying all classifier txes.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/1375e3ef175fb1c9. Report an issue: GitHub.