hcengineering/platform · error

$nin predicate requires array

Error message

$nin predicate requires array

What it means

The $nin (not-in) predicate excludes documents whose property matches any element of a supplied list, so the argument must be an array. predicate.ts throws this error during predicate construction when the value after $nin is not an Array. Like $in and $all, this mirrors MongoDB's required array argument.

Source

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

          return o.some((p) => p == value)
        }
      })
  },
  $all: (o, propertyKey) => {
    if (!Array.isArray(o)) {
      throw new Error('$all predicate requires array')
    }
    return (docs) =>
      execPredicate(docs, propertyKey, (value: any[]) => {
        for (const val of o) {
          if (!value.includes(val)) return false
        }
        return true
      })
  },
  $nin: (o, propertyKey) => {
    if (!Array.isArray(o)) {
      throw new Error('$nin predicate requires array')
    }
    return (docs) =>
      execPredicate(docs, propertyKey, (value) => {
        if (Array.isArray(value)) {
          return !o.some((p) => value.includes(p))
        } else {
          // eslint-disable-next-line eqeqeq
          return !o.some((p) => p == value)
        }
      })
  },

  $like: (query: string, propertyKey: string): Predicate => {
    const searchString = query
      .split('%')
      .map((it) => escapeLikeForRegexp(it))
      .join('.*')
    const regex = RegExp(`^${searchString}$`, 'i')

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Wrap the value(s) in an array: { $nin: ['archived'] }.
  2. Normalize dynamic input with Array.isArray and fall back to [] when absent.
  3. Split comma-separated strings before passing: str.split(',').

Example fix

// before
const q = { _class: { $nin: excluded } }
// after
const q = { _class: { $nin: Array.isArray(excluded) ? excluded : excluded != null ? [excluded] : [] } }
Defensive patterns

Strategy: validation

Validate before calling

const nin = Array.isArray(excluded) ? excluded : excluded != null ? [excluded] : []
const q = { _class: { $nin: nin } }

Type guard

function isExclusionList(v: unknown): v is unknown[] {
  return v == null || Array.isArray(v)
}

Try / catch

try {
  return await find(clazz, query)
} catch (e) {
  if (e instanceof Error && e.message.startsWith('$nin predicate requires array')) {
    return await find(clazz, { ...query, _class: { $nin: [] } })
  }
  throw e
}

Prevention

When it happens

Trigger: Queries like { status: { $nin: 'archived' } } (bare string) or { _id: { $nin: excludedIds } } where excludedIds is undefined/null/a single id object rather than an array.

Common situations: A single excluded value not wrapped in an array; ids arriving from URL params or config as a comma string; an upstream variable that is null because the exclusion list failed to load.

Related errors


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