{"record":{"id":"c738379006f0b0cc","repo":"apache/superset","slug":"invalid-filter-column-s-does-not-exist-on-s","errorCode":null,"errorMessage":"Invalid filter: column '%s' does not exist on %s","messagePattern":"Invalid filter: column '(.+?)' does not exist on (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"superset/daos/base.py","lineNumber":613,"sourceCode":"        cls, query: Any, column_operators: Optional[List[ColumnOperator]] = None\n    ) -> Any:\n        \"\"\"\n        Apply column operators (list of ColumnOperator) to the query using\n        ColumnOperatorEnum logic. Raises ValueError if a filter references a\n        non-existent column.\n        \"\"\"\n        if not column_operators:\n            return query\n        for c in column_operators:\n            if not isinstance(c, ColumnOperator):\n                continue\n            col, opr, value = c.col, c.opr, c.value\n            if not col or not hasattr(cls.model_cls, col):\n                model_name = cls.model_cls.__name__ if cls.model_cls else \"Unknown\"\n                logging.error(\n                    \"Invalid filter: column '%s' does not exist on %s\", col, model_name\n                )\n                raise ValueError(\n                    \"Invalid filter: column '%s' does not exist on %s\"\n                    % (col, model_name)\n                )\n            column = getattr(cls.model_cls, col)\n            try:\n                operator_enum = ColumnOperatorEnum(opr)\n                # Relationship attributes (many-to-many or one-to-many)\n                # can't be compared directly with scalar operators —\n                # SQLAlchemy needs `.any(...)`. Detect the collection\n                # case and dispatch to the related model's primary key\n                # column. This lets callers use the natural shapes\n                # `{col: \"<relationship>\", opr: \"eq\", value: <id>}` or\n                # `{opr: \"in\", value: [<id>, ...]}` etc. to find rows\n                # whose related collection contains those id(s).\n                is_collection_relationship = (\n                    hasattr(column, \"property\")\n                    and isinstance(column.property, RelationshipProperty)\n                    and column.property.uselist","sourceCodeStart":595,"sourceCodeEnd":631,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/daos/base.py#L595-L631","documentation":"Raised by BaseDAO.apply_column_operators() (superset/daos/base.py) when a ColumnOperator in the filters list references a column name that is empty or not an attribute of the DAO's model class (hasattr check). It is a ValueError; the same message is logged at error level first. Relationship names ARE valid here — only unknown attributes fail.","triggerScenarios":"Calling a DAO list/find API (e.g. ChartDAO.find, DashboardDAO.find) or the REST /api/v1/* resource with `filters=[{\"col\": \"nonexistent\", \"opr\": \"eq\", \"value\": 1}]`; a typo'd column name; using a column that exists on a different model than the DAO targets; col omitted/None.","commonSituations":"API clients built against an older Superset schema sending a column renamed since; MCP/tooling that guesses filter columns; passing an output/serialized field name (e.g. 'created_by_name') instead of the mapped model attribute.","solutions":["Call the resource's `/filters` endpoint (or DAO.get_filterable_columns_and_operators()) to list valid column names, then correct the filter's `col`.","Check the model class for the DAO you're calling (Slice for charts, Dashboard, SqlaTable for datasets) and use the exact SQLAlchemy attribute name.","Drop the filter entirely if it was speculative."],"exampleFix":"# before\nChartDAO.find(query=\", filters=[{\"col\": \"owners\", \"opr\": \"eq\", \"value\": 1}])\n# (Slice has no `owners` attribute)\n\n# after\nChartDAO.find(query=\", filters=[{\"col\": \"created_by_fk\", \"opr\": \"eq\", \"value\": 1}])","handlingStrategy":"validation","validationCode":"def valid_filter_cols(dao_cls, filters):\n    return all(\n        c.get(\"col\") and hasattr(dao_cls.model_cls, c[\"col\"])\n        for c in (filters or [])\n    )","typeGuard":"from superset.daos.filter import ColumnOperator\n\ndef is_known_column(model_cls, col: str | None) -> bool:\n    return bool(col) and hasattr(model_cls, col)","tryCatchPattern":"try:\n    ChartDAO.find(query=\", filters=filters)\nexcept ValueError as ex:\n    if 'does not exist on' in str(ex):\n        # drop bad filters, re-fetch valid columns, retry once\n        ...","preventionTips":["Fetch /api/v1/<resource>/filters (or DAO.get_filterable_columns_and_operators()) and validate payloads against it.","Never guess column names in generated API clients.","Use exact SQLAlchemy attribute names, not serialized output field names."],"tags":["dao","filters","api","sqlalchemy","validation"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}