{"id":"ef24ef385ec29474","repo":"drizzle-team/drizzle-orm","slug":"arraycontained-requires-at-least-one-value","errorCode":null,"errorMessage":"arrayContained requires at least one value","messagePattern":"arrayContained requires at least one value","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"drizzle-orm/src/sql/expressions/conditions.ts","lineNumber":686,"sourceCode":"export function arrayContained<T>(\n\tcolumn: SQL.Aliased<T>,\n\tvalues: (T | Placeholder) | SQLWrapper,\n): SQL;\nexport function arrayContained<TColumn extends Column>(\n\tcolumn: TColumn,\n\tvalues: (GetColumnData<TColumn, 'raw'> | Placeholder) | SQLWrapper,\n): SQL;\nexport function arrayContained<T extends SQLWrapper>(\n\tcolumn: Exclude<T, SQL.Aliased | Column>,\n\tvalues: (unknown | Placeholder)[] | SQLWrapper,\n): SQL;\nexport function arrayContained(\n\tcolumn: SQLWrapper,\n\tvalues: (unknown | Placeholder)[] | SQLWrapper,\n): SQL {\n\tif (Array.isArray(values)) {\n\t\tif (values.length === 0) {\n\t\t\tthrow new Error('arrayContained requires at least one value');\n\t\t}\n\t\tconst array = sql`${bindIfParam(values, column)}`;\n\t\treturn sql`${column} <@ ${array}`;\n\t}\n\n\treturn sql`${column} <@ ${bindIfParam(values, column)}`;\n}\n\n/**\n * Test that a column or expression contains any elements of\n * the list passed as the second argument.\n *\n * ## Throws\n *\n * The argument passed in the second array can't be empty:\n * if an empty is provided, this method will throw.\n *\n * ## Examples","sourceCodeStart":668,"sourceCodeEnd":704,"githubUrl":"https://github.com/drizzle-team/drizzle-orm/blob/b7862528fd8fc39bc2653a6c18dad7c1f4e68d10/drizzle-orm/src/sql/expressions/conditions.ts#L668-L704","documentation":"Thrown by arrayContained() when the values argument is an empty Array. arrayContained builds a '<@' (contained-by) operator expression, which has no defined meaning against an empty list, so drizzle refuses to generate it (conditions.ts:685-686). A non-array second argument (SQLWrapper or scalar) skips the check.","triggerScenarios":"Calling arrayContained(column, []); passing an array-typed filter variable that has been emptied at runtime; arrayContained(posts.tags, userSelectedTags) with userSelectedTags === [].","commonSituations":"Building a dynamic 'subset of' filter from a multi-select form field where the user cleared all selections; defaulting an optional filter to [] and forwarding it unconditionally; migrating from a raw SQL fragment that tolerated empty arrays.","solutions":["Conditionally apply the predicate only when the array is non-empty.","Treat empty input as 'match all' and skip the where clause.","Coalesce the array to a sentinel value that always satisfies the intended semantics."],"exampleFix":"// before\n.where(arrayContained(posts.tags, filterTags)) // filterTags === [] throws\n\n// after\nif (filterTags.length > 0) {\n  query.where(arrayContained(posts.tags, filterTags));\n}","handlingStrategy":"validation","validationCode":"function safeArrayContained(column, values) {\n  if (Array.isArray(values) && values.length === 0) return undefined;\n  return arrayContained(column, values);\n}","typeGuard":"const isNonEmptyArray = (v): v is unknown[] => Array.isArray(v) && v.length > 0;","tryCatchPattern":null,"preventionTips":["Guard filter arrays at the service boundary before they reach the query builder.","Prefer a predicate-skip helper over passing [] through.","Log empty-array filter inputs to catch upstream UI bugs."],"tags":["validation","postgres-array","query-builder"],"analyzedSha":"b7862528fd8fc39bc2653a6c18dad7c1f4e68d10","analyzedAt":"2026-08-03T18:11:14.318Z","schemaVersion":2}