{"record":{"id":"b8a5a035eb16c944","repo":"hcengineering/platform","slug":"lookup-class-does-not-provided-for-key-key","errorCode":null,"errorMessage":"lookup class does not provided for ${key.key}","messagePattern":"lookup class does not provided for (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/view-resources/src/utils.ts","lineNumber":470,"sourceCode":"      _class,\n      label: label as IntlString,\n      presenter: typeof presenter === 'string' ? await getResource(presenter) : presenter,\n      props: preserveKey.props,\n      displayProps: preserveKey.displayProps,\n      collectionAttr: isCollectionAttr,\n      isLookup: false\n    }\n  }\n  if (key.key.length === 0) {\n    const p = await getObjectPresenter(client, _class, preserveKey, isCollectionAttr)\n    if (p === undefined) {\n      throw new Error(`object presenter not found for class=${_class}, preserve key ${JSON.stringify(preserveKey)}`)\n    }\n    return p\n  } else {\n    if (key.key.startsWith('$lookup')) {\n      if (lookup === undefined) {\n        throw new Error(`lookup class does not provided for ${key.key}`)\n      }\n      return await getLookupPresenter(client, _class, key, preserveKey, lookup)\n    }\n    return await getAttributePresenter(client, _class, key.key, preserveKey, undefined, _category)\n  }\n}\n\nfunction getKeyLookup<T extends Doc> (\n  hierarchy: Hierarchy,\n  _class: Ref<Class<T>>,\n  key: string,\n  lookup: Lookup<T>,\n  lastIndex: number = 1\n): Lookup<T> {\n  if (!key.startsWith('$lookup')) return lookup\n  const parts = key.split('.')\n  const attrib = parts[1]\n  const attribute = hierarchy.getAttribute(_class, attrib)","sourceCodeStart":452,"sourceCodeEnd":488,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/plugins/view-resources/src/utils.ts#L452-L488","documentation":"getPresenter builds the presenter model for a view key. When the key is a $lookup key (e.g. 'attachedTo.$lookup'), a lookup definition must be supplied to resolve which class/object the lookup points at; if `lookup` is undefined the function cannot resolve the target class and throws.","triggerScenarios":"Calling getPresenter (via model()) with a BuildModelKey whose key contains '$lookup' while the corresponding Lookup<T> entry is undefined — e.g. building a view model for a lookup attribute without passing the class lookup data.","commonSituations":"Caller omitted the `lookup` argument when building models for attributes that reference other documents; view config includes $lookup keys but the client-side lookup map was not loaded; attribute is not defined in the class's lookup section.","solutions":["Provide the Lookup definition for the class when calling model()/getPresenter so $lookup keys resolve","Check the attribute has a $lookup entry in the class hierarchy/lookup data","Fall back to getAttributePresenter (non-lookup) if no lookup is intended for that key"],"exampleFix":"// before\nawait model(client, _class, [{ key: 'attachedTo.$lookup' }])\n// after\nconst lookup = await client.getLookup(_class)\nawait model(client, _class, [{ key: 'attachedTo.$lookup' }], undefined, undefined, lookup)","handlingStrategy":"validation","validationCode":"function hasLookup(lookup) { return lookup !== undefined && lookup !== null }\nif (!hasLookup(lookup)) throw new Error('lookup required for $lookup keys')\nawait model(client, _class, keys, undefined, undefined, lookup)","typeGuard":"function lookupKeysPresent(keys: { key: string }[]): boolean {\n  return keys.every(k => !k.key.includes('$lookup'))\n}","tryCatchPattern":"try {\n  return await model(client, _class, keys, undefined, undefined, lookup)\n} catch (err) {\n  if (String(err.message).startsWith('lookup class does not provided')) {\n    return await model(client, _class, keys.map(k => ({ ...k, key: k.key.replace('.$lookup', '') })))\n  }\n  throw err\n}","preventionTips":["Always load lookup data for the class before building models with $lookup keys","Validate keys against the class lookup map before calling model()","Centralize model-building in a helper that fetches lookup automatically"],"tags":["presenter","lookup","view-model","config"],"backgroundTag":"missing-lookup-definition","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}