hcengineering/platform · error

update is null

Error message

update is null

What it means

During activity-domain field migration, migrateField computes a new value and, when the value changed, needs the surrounding document update object to write update[field] = newValue. If that update object is null, a programmer/invariant error is thrown because migrations can never apply a change without a target update. This protects against silently dropping migration changes.

Source

Thrown at models/activity/src/migration.ts:306

    let newValue: any
    if (Array.isArray(oldValue)) {
      newValue = []
      for (const a of oldValue as any[]) {
        const newA = a != null ? await getUpdatedVal(a, au.attrKey) : a
        if (newA !== a) {
          changed = true
        }
        newValue.push(newA)
      }
    } else {
      newValue = await getUpdatedVal(oldValue, au.attrKey)
      if (newValue !== oldValue) {
        changed = true
      }
    }

    if (changed) {
      if (update == null) throw new Error('update is null')

      update[field] = newValue
    }
  }

  const iterator = await client.traverse(DOMAIN_ACTIVITY, {
    _class: activity.class.DocUpdateMessage,
    action: 'update',
    'attributeUpdates.attrClass': 'core:class:Account'
  })

  try {
    let processed = 0
    while (true) {
      const docs = await iterator.next(200)
      if (docs === null || docs.length === 0) {
        break
      }

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Ensure migrateAccountsInDocUpdates always passes the current doc's update object into migrateField.
  2. Add a null check before calling migrateField, skipping docs without an update payload.
  3. If you call migrateField from custom code, construct or fetch the update object before invoking it.

Example fix

// before
await migrateField(client, doc, field, null, oldValue)
// after
if (update != null) {
  await migrateField(client, doc, field, update, oldValue)
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (update == null) return // skip docs without an update payload before migrating fields

Type guard

function hasUpdate(u: unknown): u is Record<string, any> {
  return u != null && typeof u === 'object'
}

Try / catch

try {
  await migrateAccountsInDocUpdates(client)
} catch (e) {
  if (e.message === 'update is null') {
    console.error('doc update payload missing during activity migration; skipping doc')
  } else throw e
}

Prevention

When it happens

Trigger: migrateAccountsInDocUpdates iterates client.traverse(DOMAIN_ACTIVITY) doc updates and calls migrateField for each field; migrateField is invoked with update=null (or the update was destructured/lost) while the migration actually changes a value (changed=true).

Common situations: Custom migration code that reuses migrateField outside the doc-update loop; traverse returning a doc with no update payload; a refactor renaming the update parameter.

Related errors


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