drizzle-team/drizzle-orm · error · Error

arrayContains requires at least one value

Error message

arrayContains requires at least one value

What it means

Thrown by arrayContains() when the second argument is an Array with zero elements. The function builds a PostgreSQL '@>' (array-contains-all) comparison, which is semantically meaningless with an empty set, so drizzle rejects it eagerly rather than emit SQL the database would reject or misinterpret. The guard is an explicit length check at conditions.ts:637-638.

Source

Thrown at drizzle-orm/src/sql/expressions/conditions.ts:638

export function arrayContains<T>(
	column: SQL.Aliased<T>,
	values: (T | Placeholder) | SQLWrapper,
): SQL;
export function arrayContains<TColumn extends Column>(
	column: TColumn,
	values: (GetColumnData<TColumn, 'raw'> | Placeholder) | SQLWrapper,
): SQL;
export function arrayContains<T extends SQLWrapper>(
	column: Exclude<T, SQL.Aliased | Column>,
	values: (unknown | Placeholder)[] | SQLWrapper,
): SQL;
export function arrayContains(
	column: SQLWrapper,
	values: (unknown | Placeholder)[] | SQLWrapper,
): SQL {
	if (Array.isArray(values)) {
		if (values.length === 0) {
			throw new Error('arrayContains requires at least one value');
		}
		const array = sql`${bindIfParam(values, column)}`;
		return sql`${column} @> ${array}`;
	}

	return sql`${column} @> ${bindIfParam(values, column)}`;
}

/**
 * Test that the list passed as the second argument contains
 * all elements of a column or expression.
 *
 * ## Throws
 *
 * The argument passed in the second array can't be empty:
 * if an empty is provided, this method will throw.
 *
 * ## Examples

View on GitHub (pinned to b7862528fd)

Solutions

  1. Guard the caller: if (values.length) ... else skip the predicate or fall back to a safe default.
  2. Provide a meaningful fallback array (e.g. a sentinel) when the source list is empty.
  3. If 'no filter' is the intent, omit the .where(arrayContains(...)) clause entirely when values is empty.

Example fix

// before
const rows = await db.select().from(posts)
  .where(arrayContains(posts.tags, selectedTags)); // throws if selectedTags === []

// after
const qb = db.select().from(posts);
if (selectedTags.length > 0) {
  qb.where(arrayContains(posts.tags, selectedTags));
}
const rows = await qb;
Defensive patterns

Strategy: validation

Validate before calling

function safeArrayContains(column, values) {
  if (Array.isArray(values) && values.length === 0) {
    return undefined; // caller skips the predicate
  }
  return arrayContains(column, values);
}

Type guard

const isNonEmptyArray = (v): v is unknown[] => Array.isArray(v) && v.length > 0;

Prevention

When it happens

Trigger: Calling arrayContains(column, []) or passing a runtime-computed array that resolved to [], e.g. arrayContains(posts.tags, selectedTags) where selectedTags is filtered to nothing. Passing a non-array (SQLWrapper/Placeholder) never triggers it — only an empty literal/variable Array does.

Common situations: Filtering by a tags/categories array that the user deselected entirely in the UI; a search filter that produced zero selections; passing an empty default constant by mistake. Happens most often in dynamic query builders where the values list is assembled from user input.

Related errors


AI-assisted analysis of drizzle-team/drizzle-orm@b7862528fd (2026-08-03). Data as JSON: /data/errors/2c3a419848fb54c6.json. Report an issue: GitHub.