hcengineering/platform · error · Error

ancestors not found: ${_class}

Error message

ancestors not found: ${_class}

What it means

The core hierarchy (ClassModel / Hierarchy) caches ancestor lists per classifier. getAncestors throws when no ancestor list has been registered for the given class reference, meaning the class is unknown to the loaded model. Callers like ancestors/ancestors1/2/3 and updateDescendant rely on this cache being complete.

Source

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

        if (this.isMixin(d) && this.getBaseClass(d) === c._id) {
          result.add(d)
        }
      }
      c = this.getClass(c.extends)
    }

    return [...result]
  }

  isMixin (_class: Ref<Class<Doc>>): boolean {
    const data = this.classifiers.get(_class)
    return data !== undefined && this._isMixin(data)
  }

  getAncestors (_class: Ref<Classifier>): Ref<Classifier>[] {
    const result = this.ancestors.get(_class)
    if (result === undefined) {
      throw new Error('ancestors not found: ' + _class)
    }
    return result
  }

  getClass<T extends Obj = Obj>(_class: Ref<Class<T>>): Class<T> {
    const data = this.classifiers.get(_class)
    if (data === undefined || this.isInterface(data)) {
      throw new Error('class not found: ' + _class)
    }
    return data
  }

  findClass<T extends Obj = Obj>(_class: Ref<Class<T>>): Class<T> | undefined {
    const data = this.classifiers.get(_class)
    if (data === undefined || this.isInterface(data)) {
      return undefined
    }
    return data

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Ensure the model is fully loaded (await client.getModel / initialize) before hierarchy queries.
  2. Verify the class Ref exists and its defining plugin is included in the deployment.
  3. Use findClass/hierarchy.isDerived defensively instead of assuming the class is registered.
  4. Check plugin versions align across client and server (the class may be newer or removed).
  5. Catch the error and treat the class as unknown rather than crashing derived-data updates.

Example fix

// before
const anc = hierarchy.getAncestors(task.class.Class)
// after
const anc = hierarchy.getAncestors(task.class.Class) // throws if unknown
// safer:
const cls = hierarchy.findClass(task.class.Class)
const anc = cls !== undefined ? hierarchy.getAncestors(task.class.Class) : []
Defensive patterns

Strategy: type-guard

Validate before calling

const cls = hierarchy.findClass(_class)
if (cls === undefined) {
  console.warn(`Class ${_class} not in model — plugin missing or model not loaded`)
}

Type guard

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

Try / catch

let ancestors: Ref<Classifier>[]
try {
  ancestors = hierarchy.getAncestors(_class)
} catch (err) {
  if (err.message.startsWith('ancestors not found')) {
    ancestors = [] // unknown class — treat as root
  } else {
    throw err
  }
}

Prevention

When it happens

Trigger: Calling getAncestors (directly or via ancestors*, updateDescendant) with a class Ref that was never registered in the model — e.g. before model loading completes, after a partial model load, or with a class ref from a plugin not included in the build.

Common situations: Querying with a class from a plugin/translation whose model wasn't loaded; calling hierarchy APIs before client/model initialization finishes; typo'd or renamed class Ref after a model version change; mixed plugin versions where one side defines classes the other doesn't know.

Related errors


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