hcengineering/platform · error

object presenter not found for class=${_class}, preserve key

Error message

object presenter not found for class=${_class}, preserve key ${JSON.stringify(preserveKey)}

What it means

getPresenter falls back to getObjectPresenter to render a whole object when the key resolves to an empty key (an object-level presenter, e.g. for a lookup reference cell). It throws when no object presenter is registered for the given class. Like the attribute-presenter error, it signals a missing UI registration for that class.

Source

Thrown at plugins/view-resources/src/utils.ts:464

): Promise<AttributeModel> {
  if (key.presenter !== undefined) {
    const { presenter, label, sortingKey } = key
    return {
      key: key.key ?? '',
      sortingKey: sortingKey ?? '',
      _class,
      label: label as IntlString,
      presenter: typeof presenter === 'string' ? await getResource(presenter) : presenter,
      props: preserveKey.props,
      displayProps: preserveKey.displayProps,
      collectionAttr: isCollectionAttr,
      isLookup: false
    }
  }
  if (key.key.length === 0) {
    const p = await getObjectPresenter(client, _class, preserveKey, isCollectionAttr)
    if (p === undefined) {
      throw new Error(`object presenter not found for class=${_class}, preserve key ${JSON.stringify(preserveKey)}`)
    }
    return p
  } else {
    if (key.key.startsWith('$lookup')) {
      if (lookup === undefined) {
        throw new Error(`lookup class does not provided for ${key.key}`)
      }
      return await getLookupPresenter(client, _class, key, preserveKey, lookup)
    }
    return await getAttributePresenter(client, _class, key.key, preserveKey, undefined, _category)
  }
}

function getKeyLookup<T extends Doc> (
  hierarchy: Hierarchy,
  _class: Ref<Class<T>>,
  key: string,
  lookup: Lookup<T>,

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Register a default object presenter for the class (view.component.ObjectPresenter per-class registration).
  2. Verify the class id and preserveKey; ensure the lookup provides the correct lookup class.
  3. Ensure the contributing plugin is installed/loaded.
  4. Provide an explicit presenter/component for the cell instead of relying on defaults.

Example fix

// before
const p = await getPresenter(client, myCustomClass, key)
// after
setObjectPresenter(myCustomClass, myPlugin.component.MyCardPresenter) // register first
const p = await getPresenter(client, myCustomClass, key)
Defensive patterns

Strategy: fallback

Validate before calling

const p = await getObjectPresenter(client, _class) ?? defaultObjectPresenter

Type guard

function hasObjectPresenter(cls: Ref<Class<Doc>>): boolean { return getObjectPresenterSync(cls) !== undefined }

Try / catch

try { return await getPresenter(client, _class, key) } catch { return genericObjectPresenter }

Prevention

When it happens

Trigger: Rendering a reference/lookup column (or any key where key.key.length === 0) for a class that has no object presenter registered via getObjectPresenter registry.

Common situations: Custom/derived classes without a default presenter; lookup keys ($lookup...) used where the target class lacks a presenter; plugin with the object presenter not loaded; class renamed/refactored leaving the registry stale.

Related errors


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