{"id":"0788a8708d69c651","repo":"sqlalchemy/sqlalchemy","slug":"array-contains-not-implemented-for-the-base-arra","errorCode":null,"errorMessage":"ARRAY.contains() not implemented for the base ARRAY type; please use the dialect-specific ARRAY type","messagePattern":"ARRAY\\.contains\\(\\) not implemented for the base ARRAY type; please use the dialect-specific ARRAY type","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"lib/sqlalchemy/sql/sqltypes.py","lineNumber":3213,"sourceCode":"                if arr_type.dimensions is None or arr_type.dimensions == 1:\n                    return_type = arr_type.item_type\n                else:\n                    adapt_kw = {\"dimensions\": arr_type.dimensions - 1}\n                    return_type = arr_type.adapt(\n                        arr_type.__class__, **adapt_kw\n                    )\n\n                return operators.getitem, index, return_type\n\n        def contains(self, *arg: Any, **kw: Any) -> ColumnElement[bool]:\n            \"\"\"``ARRAY.contains()`` not implemented for the base ARRAY type.\n            Use the dialect-specific ARRAY type.\n\n            .. seealso::\n\n                :class:`_postgresql.ARRAY` - PostgreSQL specific version.\n            \"\"\"\n            raise NotImplementedError(\n                \"ARRAY.contains() not implemented for the base \"\n                \"ARRAY type; please use the dialect-specific ARRAY type\"\n            )\n\n        @util.deprecated(\n            \"2.1\",\n            message=\"The :meth:`_types.ARRAY.Comparator.any` and \"\n            \":meth:`_types.ARRAY.Comparator.all` methods for arrays are \"\n            \"deprecated for removal, along with the PG-specific \"\n            \":func:`_postgresql.Any` and \"\n            \":func:`_postgresql.All` functions. See :func:`_sql.any_` and \"\n            \":func:`_sql.all_` functions for modern use.\",\n        )\n        @util.preload_module(\"sqlalchemy.sql.elements\")\n        def any(\n            self, other: Any, operator: Optional[OperatorType] = None\n        ) -> ColumnElement[bool]:\n            \"\"\"Return ``other operator ANY (array)`` clause.","sourceCodeStart":3195,"sourceCodeEnd":3231,"githubUrl":"https://github.com/sqlalchemy/sqlalchemy/blob/d9b44cb731bd27e6e82c99a3c0fb598214e8e7ff/lib/sqlalchemy/sql/sqltypes.py#L3195-L3231","documentation":"Raised by the base ARRAY.Comparator.contains() method (sqltypes.py:3213) because the generic ARRAY type does not define a portable 'contains' operator. Only dialect-specific ARRAY types (notably sqlalchemy.dialects.postgresql.ARRAY) implement array containment (@>). The base class deliberately raises NotImplementedError to steer you to the dialect type.","triggerScenarios":"Calling MyTable.col.contains([...]) where col is typed with the generic sqlalchemy.types.ARRAY rather than the PostgreSQL-specific ARRAY; using the base ARRAY with a backend (or in-memory compilation) that does not provide a contains operator.","commonSituations":"Defining a cross-database model with generic ARRAY then attempting PostgreSQL-style containment queries; copy-paste of PG examples into a model that imported ARRAY from the top-level package; forgetting to switch the column type after deciding to target PostgreSQL.","solutions":["Change the column type to sqlalchemy.dialects.postgresql.ARRAY, whose Comparator implements contains() via the @> operator.","Rewrite the predicate using a portable expression such as .any()/.all_() (note any/all are deprecated in 2.1 in favor of sqlalchemy.sql.any_/all_) or a raw text/func construct.","If multi-database support is required, branch the query construction per dialect instead of relying on the base ARRAY."],"exampleFix":"// before\nfrom sqlalchemy import Column, ARRAY, Integer\namounts = Column(ARRAY(Integer))\nstmt = select(T).where(T.amounts.contains([5]))\n\n// after\nfrom sqlalchemy.dialects.postgresql import ARRAY as PG_ARRAY\namounts = Column(PG_ARRAY(Integer))\nstmt = select(T).where(T.amounts.contains([5]))","handlingStrategy":"type-guard","validationCode":"from sqlalchemy.sql.sqltypes import ARRAY as GenericARRAY\n\ndef assert_dialect_array_supports_contains(col_type):\n    # Generic ARRAY does not implement .contains(); only dialect arrays do.\n    if type(col_type) is GenericARRAY:\n        raise TypeError(\n            \"Use a dialect-specific ARRAY (e.g. sqlalchemy.dialects.postgresql.ARRAY) \"\n            \"to call .contains().\"\n        )\n    return col_type","typeGuard":"from sqlalchemy.sql.sqltypes import ARRAY as GenericARRAY\n\ndef supports_contains(col_type) -> bool:\n    # Generic base ARRAY returns True only for dialect subclasses.\n    return not type(col_type) is GenericARRAY","tryCatchPattern":"try:\n    stmt = select(MyTable).where(MyTable.tags.contains([\"x\"]))\nexcept NotImplementedError as err:\n    if \"contains() not implemented\" in str(err):\n        # fall back to a portable operator, e.g. overlap (&&) or any():\n        stmt = select(MyTable).where(MyTable.tags.any(lambda t: t == \"x\"))\n    else:\n        raise","preventionTips":["Import ARRAY from the target dialect (`from sqlalchemy.dialects.postgresql import ARRAY`) when you need `.contains()` or other array operators.","Prefer portable expressions like `.any()`/`.all()` or raw operators (`&&`, `@>`) over `.contains()` if you may run on multiple dialects.","In a model registry, record which columns are dialect-specific so generic ARRAYs are never queried with contains()."],"tags":["array","contains","postgresql","notimplementederror"],"analyzedSha":"d9b44cb731bd27e6e82c99a3c0fb598214e8e7ff","analyzedAt":"2026-08-01T17:20:52.075Z","schemaVersion":2}