hcengineering/platform · error

attribute presenter not found for ${JSON.stringify(preserveK

Error message

attribute presenter not found for ${JSON.stringify(preserveKey)}

What it means

getAttributePresenter resolves a presenter function for a class/key combination via findAttributePresenter and throws when none is registered. Presenters are how the UI renders attribute values; an unregistered presenter means the framework does not know how to display that attribute. The preserveKey in the message identifies exactly which key failed.

Source

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

export async function getAttributePresenter (
  client: Client,
  _class: Ref<Class<Obj>>,
  key: string,
  preserveKey: BuildModelKey,
  mixinClass?: Ref<Mixin<CollectionPresenter>>,
  _category?: AttributeCategory
): Promise<AttributeModel> {
  const actualMixinClass = mixinClass ?? view.mixin.AttributePresenter
  const hierarchy = client.getHierarchy()
  const attribute = hierarchy.getAttribute(_class, key)
  let { attrClass, category } = getAttributePresenterClass(hierarchy, attribute.type)
  if (_category !== undefined) {
    category = _category
  }

  const presenterRef = findAttributePresenter(client, _class, key, actualMixinClass, category)
  if (presenterRef === undefined) {
    throw new Error('attribute presenter not found for ' + JSON.stringify(preserveKey))
  }

  const isCollectionAttr = category === 'collection'

  const mixin = isCollectionAttr ? view.mixin.CollectionPresenter : actualMixinClass

  let presenterMixin: AttributePresenter | CollectionPresenter | undefined = hierarchy.classHierarchyMixin(
    attrClass,
    mixin
  )

  if (presenterMixin?.presenter === undefined && mixinClass != null && mixin === mixinClass) {
    presenterMixin = hierarchy.classHierarchyMixin(attrClass, view.mixin.AttributePresenter)
  }

  const resultKey = preserveKey.sortingKey ?? preserveKey.key
  const sortingKey = Array.isArray(resultKey)
    ? resultKey

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Register a presenter for the attribute's type/class (addPresenter for the type class or mixin).
  2. Check the key and mixin class passed to getAttributePresenter for typos.
  3. Ensure the plugin that contributes the presenter is included in the build/assembly.
  4. Fall back to a default text presenter for unknown types.

Example fix

// before
const presenter = getPresenter(client, myClass, 'customField')
// after
addPresenter(myTypeClass, plugin.component.TextPresenter) // register first
const presenter = getAttributePresenterSafe(client, myClass, 'customField') ?? textPresenter
Defensive patterns

Strategy: fallback

Validate before calling

import { getAttributePresenterSafe } from '@hcengineering/view-resources'
const presenter = getAttributePresenterSafe(client, _class, key) ?? defaultTextPresenter

Type guard

function hasPresenter(h: Hierarchy, cls: Ref<Class<Doc>>, key: string): boolean { return findAttributePresenter(client, cls, key) !== undefined }

Try / catch

try { return await getAttributePresenter(client, _class, key) } catch { return textPresenter }

Prevention

When it happens

Trigger: Rendering a component with a key (_class + key, possibly mixin class or category like 'collection') for which no presenter was registered, including built-in types missing from the presenter map.

Common situations: Custom data types without a registered presenter; typos in keys; plugin providing the presenter not loaded; new attribute types added after a version upgrade where the old presenter map lacks them; rendering collection attributes without a CollectionPresenter.

Related errors


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