{"record":{"id":"28efe6efa26b07fe","repo":"hcengineering/platform","slug":"process-error-relationnotexists","errorCode":"process.error.RelationNotExists","errorMessage":"Relation not exists: {association}","messagePattern":"Relation not exists: (.+?)","errorType":"exception","errorClass":"ProcessError","httpStatus":null,"severity":"error","filePath":"server-plugins/process-resources/src/utils.ts","lineNumber":192,"sourceCode":"    throw processError(\n      process.error.EmptyRelatedObjectValue,\n      {},\n      { parent: attr.label, attr: nested?.label ?? getEmbeddedLabel(context.key) }\n    )\n  }\n  return val\n}\n\nasync function getRelationValue (\n  control: ProcessControl,\n  execution: Execution,\n  context: SelectedRelation\n): Promise<any> {\n  const _process = control.client.getModel().findObject(execution.process)\n  if (_process === undefined) throw processError(process.error.ObjectNotFound, { _id: execution.process })\n  const realAssociation = resolveAttributeId(_process, context.association)\n  const assoc = control.client.getModel().findObject(realAssociation)\n  if (assoc === undefined) throw processError(process.error.RelationNotExists, {})\n  const targetClass = context.direction === 'A' ? assoc.classA : assoc.classB\n  const q = context.direction === 'A' ? { docB: execution.card } : { docA: execution.card }\n  const relations = await control.client.findAll(core.class.Relation, { association: assoc._id, ...q })\n  const name = context.direction === 'A' ? assoc.nameA : assoc.nameB\n  const shouldBeArray = assoc.type === 'N:N' || (assoc.type === '1:N' && context.direction === 'A')\n  if (relations.length === 0) {\n    if (shouldBeArray) return []\n    throw processError(process.error.RelatedObjectNotFound, { attr: name })\n  }\n  const ids = relations.map((it) => {\n    return context.direction === 'A' ? it.docA : it.docB\n  })\n  const target = await control.client.findAll(targetClass, { _id: { $in: ids } })\n  if (target.length === 0) throw processError(process.error.RelatedObjectNotFound, { attr: context.name })\n  const realKey = resolveAttributeId(_process, context.key)\n  const attr = realKey !== '' ? control.client.getHierarchy().findAttribute(targetClass, realKey) : undefined\n  if (context.sourceFunction !== undefined) {\n    const transform = control.client.getModel().findObject(context.sourceFunction.func)","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/server-plugins/process-resources/src/utils.ts#L174-L210","documentation":"Thrown when the association referenced by the relation context (context.association, after resolveAttributeId) does not resolve to an object in the model. The library needs the association definition to determine target class and direction, so it throws RelationNotExists.","triggerScenarios":"getRelationValue: resolveAttributeId(_process, context.association) returns an id for which control.client.getModel().findObject returns undefined.","commonSituations":"Association removed/renamed while the process template still selects it; template exported from a workspace without the association; id typo or wrong association id configured in the activity.","solutions":["Verify the association id in the process template exists in the model and fix the reference","Recreate the association definition (or re-import the plugin that defines it)","Re-select the association in the process builder so the correct id is stored","Sync model definitions between environments to include the association"],"exampleFix":"// before\nassociation: 'assoc.project-old' // removed\n// after\nassociation: 'assoc.project-task' // existing association id","handlingStrategy":"validation","validationCode":"const realAssociation = resolveAttributeId(_process, ctx.association)\nif (control.client.getModel().findObject(realAssociation) === undefined) {\n  throw new Error(`Association ${ctx.association} does not exist`)\n}","typeGuard":"function associationExists(model: Model, associationId: string): boolean {\n  return model.findObject(associationId) !== undefined\n}","tryCatchPattern":"try {\n  val = await getRelationValue(control, execution, ctx)\n} catch (err) {\n  if ((err as any)?.code === 'process.error.RelationNotExists') {\n    throw new Error(`Configured association missing: ${ctx.association}`)\n  }\n  throw err\n}","preventionTips":["Select associations via the model UI/API rather than typing ids","Re-validate relation contexts after removing/renaming associations","Include association definitions when exporting templates between workspaces","Add a template validation step that checks all association ids"],"tags":["process","association","model-reference"],"backgroundTag":"relation-not-exists","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}