hcengineering/platform · error

Add collection step must have attachedTo, attachedToClass, c

Error message

Add collection step must have attachedTo, attachedToClass, collection and space

What it means

The initializer's create() method has a special branch for 'add collection' migration steps, which require attachedTo, attachedToClass, collection and space in the step data. If any of these four fields is undefined, the step is malformed and the migration cannot attach a collection, so it throws immediately before calling client.addCollection. This is a fail-fast validation of the migration/fixture data shape.

Source

Thrown at server/tool/src/initializer.ts:300

  }

  private parseMarkdown (text: string): string {
    const json = markdownToMarkup(text ?? '', { imageUrl: this.imageUrl })
    return JSON.stringify(json)
  }

  private async create<T extends Doc>(_class: Ref<Class<T>>, data: Props<T>, _id?: Ref<T>): Promise<Ref<T>> {
    const hierarchy = this.client.getHierarchy()

    if (hierarchy.isDerived(_class, core.class.AttachedDoc)) {
      const { space, attachedTo, attachedToClass, collection, ...props } = data as unknown as Props<AttachedDoc>
      if (
        attachedTo === undefined ||
        space === undefined ||
        attachedToClass === undefined ||
        collection === undefined
      ) {
        throw new Error('Add collection step must have attachedTo, attachedToClass, collection and space')
      }
      return (await this.client.addCollection(
        _class,
        space,
        attachedTo,
        attachedToClass,
        collection,
        props,
        _id as Ref<AttachedDoc> | undefined
      )) as unknown as Ref<T>
    } else {
      const { space, ...props } = data
      if (space === undefined) {
        throw new Error('Create step must have space')
      }
      return await this.client.createDoc<T>(_class, space, props as Data<T>, _id)
    }
  }

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Add all four required fields (attachedTo, attachedToClass, collection, space) to the step data
  2. Log the data object before calling create() to see which field is undefined
  3. Check the upstream code that constructs the step for a key typo or failed lookup returning undefined

Example fix

// before
await initializer.create(_class, { collection: 'comments' } as any)
// after
await initializer.create(_class, {
  attachedTo: parentId,
  attachedToClass: 'task:task:Task',
  collection: 'comments',
  space: mySpace
})
Defensive patterns

Strategy: validation

Validate before calling

function isValidAddCollectionStep(data) {
  return data != null &&
    data.attachedTo !== undefined &&
    data.attachedToClass !== undefined &&
    data.collection !== undefined &&
    data.space !== undefined
}
if (!isValidAddCollectionStep(step)) throw new Error('Invalid add collection step: ' + JSON.stringify(step))

Type guard

function isAddCollectionStep(d: unknown): d is { attachedTo: Ref<Doc>, attachedToClass: string, collection: string, space: Ref<Space> } & Record<string, any> {
  const o = d as any
  return o != null && typeof o.collection === 'string' && o.attachedTo !== undefined && o.attachedToClass !== undefined && o.space !== undefined
}

Try / catch

try {
  await initializer.create(_class, data)
} catch (err) {
  if (err instanceof Error && err.message.includes('Add collection step must have')) {
    console.error('Malformed add-collection step, missing fields:', data)
  }
  throw err
}

Prevention

When it happens

Trigger: Calling create() (via processCreate) with a _class that resolves to the add-collection branch while the data object omits or misspells one of attachedTo, attachedToClass, collection or space (e.g. fields set to undefined by a spread or upstream transform).

Common situations: Migration step objects built dynamically where a variable was undefined; typos in step keys (e.g. attachedTo missing because the parent doc id wasn't resolved); copy-pasted step definitions from a different step type that doesn't carry collection fields.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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