hcengineering/platform · error · ProcessError

process.error.AttributeNotExists

process.error.AttributeNotExists

Error message

Attribute not exists: {key}

What it means

Thrown by getNestedValue when the resolved path (realPath) does not correspond to any attribute on the card's class according to control.client.getHierarchy().findAttribute. The nested context references a path that does not exist on the target object.

Source

Thrown at server-plugins/process-resources/src/utils.ts:135

    if (transform === undefined) throw processError(process.error.MethodNotFound, { methodId: func.func }, {}, true)
    if (!control.client.getHierarchy().hasMixin(transform, serverProcess.mixin.FuncImpl)) {
      throw processError(process.error.MethodNotFound, { methodId: func.func }, {}, true)
    }
    const funcImpl = control.client.getHierarchy().as(transform, serverProcess.mixin.FuncImpl)
    const f = await getResource(funcImpl.func)
    value = await f(value, func.props, control, execution)
  }
  return value
}

async function getNestedValue (control: ProcessControl, execution: Execution, context: SelectedNested): Promise<any> {
  const card = control.cache.get(execution.card)
  if (card === undefined) throw processError(process.error.ObjectNotFound, { _id: execution.card }, {}, true)
  const _process = control.client.getModel().findObject(execution.process)
  if (_process === undefined) throw processError(process.error.ObjectNotFound, { _id: execution.process })
  const realPath = resolveAttributeId(_process, context.path)
  const attr = control.client.getHierarchy().findAttribute(card._class, realPath)
  if (attr === undefined) throw processError(process.error.AttributeNotExists, { key: realPath })
  const nestedValue = getValue(control, execution, context.path, card)
  if (nestedValue === undefined) throw processError(process.error.EmptyAttributeContextValue, {}, { attr: attr.label })
  const parentType = attr.type._class === core.class.ArrOf ? (attr.type as ArrOf<Doc>).of : attr.type
  const targetClass = parentType._class === core.class.RefTo ? (parentType as RefTo<Doc>).to : parentType._class
  const refs = Array.isArray(nestedValue) ? nestedValue : [nestedValue]
  const target = await control.client.findAll(targetClass, {
    _id: { $in: refs }
  })
  if (target.length === 0) throw processError(process.error.RelatedObjectNotFound, {}, { attr: attr.label })
  const realKey = resolveAttributeId(_process, context.key)
  const nested = control.client.getHierarchy().findAttribute(targetClass, realKey)
  if (context.sourceFunction !== undefined) {
    const transform = control.client.getModel().findObject(context.sourceFunction.func)
    if (transform === undefined) {
      throw processError(process.error.MethodNotFound, { methodId: context.sourceFunction.func }, {}, true)
    }
    if (!control.client.getHierarchy().hasMixin(transform, serverProcess.mixin.FuncImpl)) {
      throw processError(process.error.MethodNotFound, { methodId: context.sourceFunction.func }, {}, true)

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Check context.path resolves to a real attribute on the card's class (inspect hierarchy.findAttribute result).
  2. Update the process template's nested path after schema renames/migrations.
  3. Apply the required mixin to the card's class if the attribute is mixin-provided.
  4. Validate paths against the hierarchy at template design/save time.

Example fix

// before: blind nested access
path: 'customField.oldName'
// after: verify attribute exists
const attr = control.client.getHierarchy().findAttribute(card._class, resolveAttributeId(_process, 'customField.oldName'))
if (attr === undefined) throw new Error('Path not found on ' + card._class)
Defensive patterns

Strategy: validation

Validate before calling

const realPath = resolveAttributeId(_process, context.path)
if (control.client.getHierarchy().findAttribute(card._class, realPath) === undefined) {
  throw new Error(`Attribute ${realPath} does not exist on ${card._class}`)
}

Type guard

function attributeExists(hierarchy: Hierarchy, _class: Ref<Class<Doc>>, key: string): boolean {
  return hierarchy.findAttribute(_class, key) !== undefined
}

Try / catch

try {
  const value = await getNestedValue(control, execution, ctx)
} catch (err) {
  if ((err as Error).message.startsWith('Attribute not exists')) {
    // correct the path in the template
  } else throw err
}

Prevention

When it happens

Trigger: getContextValue → getNestedValue where context.path (after resolveAttributeId mapping against the process) yields a key not present in the hierarchy for card._class — renamed attributes, wrong class, or missing mixin providing the attribute.

Common situations: Process templates written against an older schema; attributes moved into mixins that are not applied to the card's class; typos in nested paths; platform version changes renaming attributes.

Related errors


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