{"record":{"id":"0e3fb1a86107151d","repo":"apache/superset","slug":"invalid-order-column-order-column","errorCode":null,"errorMessage":"Invalid order column: {order_column}","messagePattern":"Invalid order column: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"superset/daos/datasource.py","lineNumber":198,"sourceCode":"\n    @staticmethod\n    def paginate_combined_query(\n        combined: Any,\n        order_column: str,\n        order_direction: str,\n        page: int,\n        page_size: int,\n    ) -> tuple[int, list[Any]]:\n        \"\"\"Count, sort, and paginate the combined dataset/semantic-view query.\"\"\"\n        sort_col_map = {\n            \"changed_on\": \"changed_on\",\n            \"changed_on_delta_humanized\": \"changed_on\",\n            \"table_name\": \"table_name\",\n            \"database.database_name\": \"database_name\",\n            \"schema\": \"schema\",\n        }\n        if order_column not in sort_col_map:\n            raise ValueError(f\"Invalid order column: {order_column}\")\n        sort_col_name = sort_col_map[order_column]\n\n        total_count = (\n            db.session.execute(select(func.count()).select_from(combined)).scalar() or 0\n        )\n\n        sort_col = combined.c[sort_col_name]\n        ordered_col = sort_col.desc() if order_direction == \"desc\" else sort_col.asc()\n\n        rows = db.session.execute(\n            select(combined.c.item_id, combined.c.source_type)\n            .order_by(ordered_col)\n            .offset(page * page_size)\n            .limit(page_size)\n        ).fetchall()\n\n        return total_count, rows\n","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/daos/datasource.py#L180-L216","documentation":"Raised inside the combined dataset/semantic-view pagination helper in superset/daos/datasource.py when the order_column parameter is not one of the five whitelisted keys in sort_col_map: changed_on, changed_on_delta_humanized, table_name, database.database_name, schema. It is a plain ValueError (not a SupersetException), so unless a caller catches it, it surfaces as an HTTP 500 rather than a 400. The map exists because the sorted query is a UNION of dataset and semantic-view selects that only exposes those aliased columns.","triggerScenarios":"Calling the dataset/semantic-view list API or the underlying DAO pagination method with order_column='name', 'created_on', or any frontend sort field not present in sort_col_map; a custom API client passing an arbitrary column name; frontend changes renaming a table column without updating the backend whitelist.","commonSituations":"Custom UI skins or forks that add sortable columns to the dataset list; version skew where the frontend sorts on a column the backend whitelist never received; scripts hitting /api/v1/dataset pagination endpoints with hand-built order_column values.","solutions":["Use only the supported sort keys: 'changed_on', 'changed_on_delta_humanized', 'table_name', 'database.database_name', or 'schema'.","If you need a new sortable column, add it to sort_col_map in the pagination method AND ensure the combined UNION select actually exposes that column, then update API schemas/tests.","As an API caller, validate order_column against the whitelist before issuing the request so you get a clean client-side error instead of a 500.","Check superset-frontend for the dataset list column definitions to confirm which order_column strings it sends."],"exampleFix":"# before\nfetch_dataset_page(order_column='name', order_direction='asc')  # ValueError\n\n# after\nALLOWED = {'changed_on', 'changed_on_delta_humanized', 'table_name', 'database.database_name', 'schema'}\ncol = order_column if order_column in ALLOWED else 'changed_on'\nfetch_dataset_page(order_column=col, order_direction=order_direction)","handlingStrategy":"validation","validationCode":"SORTABLE_COLUMNS = {\n    'changed_on', 'changed_on_delta_humanized',\n    'table_name', 'database.database_name', 'schema',\n}\n\ndef safe_order_column(col: str | None) -> str:\n    return col if col in SORTABLE_COLUMNS else 'changed_on'","typeGuard":"def is_sortable_dataset_column(col: object) -> TypeGuard[str]:\n    return col in {\n        'changed_on', 'changed_on_delta_humanized',\n        'table_name', 'database.database_name', 'schema',\n    }","tryCatchPattern":"try:\n    total, rows = paginate_datasets(combined, order_column, order_direction, page, page_size)\nexcept ValueError as err:\n    if 'Invalid order column' in str(err):\n        return bad_request(str(err))  # convert DAO ValueError into a 400 response\n    raise","preventionTips":["Validate order_column against a single shared constant used by both frontend and backend.","Treat the sort whitelist as part of the API contract; update schemas and tests when adding columns.","Default invalid sort inputs to 'changed_on' in defensive clients instead of erroring."],"tags":["dao","pagination","sorting","validation","api-misuse"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}