hcengineering/platform · error

$size predicate requires array

Error message

$size predicate requires array

What it means

$size matches documents whose property is an array of a particular length. Unlike $in/$all/$nin, this check happens at evaluation time against the document's field value: when a matched document's property is not an array (or is a non-null scalar/object), predicate.ts throws this error while running the query. It indicates the queried field does not consistently hold arrays.

Source

Thrown at foundations/core/packages/core/src/predicate.ts:121

  },
  $lte: (o, propertyKey) => {
    return (docs) => execPredicate(docs, propertyKey, (value) => value <= o)
  },
  $exists: (o, propertyKey) => {
    return (docs) => execPredicate(docs, propertyKey, (value) => (value !== undefined) === o)
  },
  $ne: (o, propertyKey) => {
    // eslint-disable-next-line eqeqeq
    return (docs) => execPredicate(docs, propertyKey, (value) => (o != null ? !deepEqual(o, value) : value != null))
  },
  $size: (o, propertyKey) => {
    return (docs) =>
      execPredicate(docs, propertyKey, (value) => {
        if (value == null) {
          return false
        }
        if (!Array.isArray(value)) {
          throw new Error('$size predicate requires array')
        }
        if (typeof o === 'number') {
          return value.length === o
        }
        if (typeof o === 'object' && o.$gt !== undefined) {
          return value.length > o.$gt
        }
        if (typeof o === 'object' && o.$gte !== undefined) {
          return value.length >= o.$gte
        }
        if (typeof o === 'object' && o.$lt !== undefined) {
          return value.length < o.$lt
        }
        if (typeof o === 'object' && o.$lte !== undefined) {
          return value.length <= o.$lte
        }
        return false
      })

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Fix the data so the field is always an array (migrate single values to [value]).
  2. Ensure write paths always assign arrays, even for one element.
  3. Pre-filter or $exists-guard the field, or use a different predicate ($exists, $ne) for non-array fields.
  4. Wrap query execution in try/catch if heterogeneous legacy data must be tolerated.

Example fix

// before (writer)
await update(doc, { $set: { attachments: file } })
// after
await update(doc, { $set: { attachments: [file] } })
Defensive patterns

Strategy: validation

Validate before calling

// Before querying with $size, ensure the field holds arrays everywhere
const bad = docs.find((d) => d.attachments != null && !Array.isArray(d.attachments))
if (bad != null) throw new Error(`doc ${bad._id} has non-array attachments; migrate before using $size`)

Type guard

function hasArrayField<K extends string>(doc: Record<string, unknown>, key: K): doc is Record<K, unknown[]> {
  return Array.isArray(doc[key])
}

Try / catch

try {
  return await find(clazz, { attachments: { $size: 3 } })
} catch (e) {
  if (e instanceof Error && e.message.startsWith('$size predicate requires array')) {
    // fall back: filter in code over non-array-tolerant predicate
    const all = await find(clazz, { attachments: { $exists: true } })
    return all.filter((d) => Array.isArray(d.attachments) && d.attachments.length === 3)
  }
  throw e
}

Prevention

When it happens

Trigger: Querying { attachments: { $size: 3 } } when some documents store attachments as undefined-is-guarded (returns false) but others store a scalar or a plain object (e.g. a single attachment object instead of an array) — evaluation then throws on those docs.

Common situations: Schema drift where older documents or imports stored the field as a single value; data written by another tool/version with a different shape; optional fields populated inconsistently across documents.

Related errors


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