{"record":{"id":"742129a05d5f85eb","repo":"apache/superset","slug":"virtual-dataset-query-cannot-be-empty","errorCode":null,"errorMessage":"Virtual dataset query cannot be empty","messagePattern":"Virtual dataset query cannot be empty","errorType":"exception","errorClass":"SupersetGenericDBErrorException","httpStatus":400,"severity":"error","filePath":"superset/connectors/sqla/utils.py","lineNumber":109,"sourceCode":"            col.update(\n                {\n                    \"type\": \"UNKNOWN\",\n                    \"type_generic\": None,\n                    \"is_dttm\": None,\n                }\n            )\n    return cols\n\n\ndef _has_jinja_markers(sql: str) -> bool:\n    \"\"\"Return True if ``sql`` contains Jinja template markers (``{%`` or ``{{``).\"\"\"\n    return \"{%\" in sql or \"{{\" in sql\n\n\ndef get_virtual_table_metadata(dataset: SqlaTable) -> list[ResultSetColumnType]:\n    \"\"\"Use SQLparser to get virtual dataset metadata\"\"\"\n    if not dataset.sql:\n        raise SupersetGenericDBErrorException(\n            message=_(\"Virtual dataset query cannot be empty\"),\n        )\n\n    db_engine_spec = dataset.database.db_engine_spec\n    original_sql = dataset.sql\n    try:\n        sql = dataset.get_template_processor().process_template(\n            original_sql, **dataset.template_params_dict\n        )\n    except SupersetSyntaxErrorException as ex:\n        # ``process_template`` aggregates several jinja2 exceptions\n        # (``TemplateSyntaxError``, ``SecurityError``, ``UndefinedError``,\n        # ``Unicode*Error``) into ``SupersetSyntaxErrorException``. Only\n        # the ``UndefinedError`` case is a \"missing runtime context\"\n        # signal that ``RefreshDatasetCommand`` can safely soften — the\n        # rest (sandbox violations, malformed template syntax, encoding\n        # errors) indicate a real problem with the template that must\n        # surface. See #38012.","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/connectors/sqla/utils.py#L91-L127","documentation":"SupersetGenericDBErrorException raised in get_virtual_table_metadata (utils.py:109) when a dataset flagged as virtual has an empty/None sql attribute. Virtual datasets are defined entirely by their SQL; with no SQL there is nothing to parse or execute, so metadata retrieval fails immediately before template processing.","triggerScenarios":"Saving a dataset with kind='virtual' (or sql null/blank) — e.g. the UI allowed creating a virtual dataset without SQL, an import/migration produced one, or a script created the row directly. Any operation needing metadata (Explore, chart data, dataset list) triggers it.","commonSituations":"Dataset YAML import with missing sql field; API-created datasets omitting sql; datasets whose SQL was cleared during editing; migration scripts copying dataset rows incompletely.","solutions":["Open the dataset in the editor and provide the virtual dataset's SQL query, then save.","If the dataset should be physical, set its kind to physical (table-based) with correct table_name/schema instead of leaving an empty virtual definition.","Audit for other broken rows: SELECT id, table_name FROM tables WHERE kind='virtual' AND (sql IS NULL OR sql='');"],"exampleFix":"# before\nDataset(kind='virtual', table_name='my_vds', sql=None)\n\n# after\nDataset(kind='virtual', table_name='my_vds', sql='SELECT id, amt FROM sales WHERE amt > 0')","handlingStrategy":"validation","validationCode":"def validate_virtual_dataset(dataset) -> None:\n    if getattr(dataset, \"kind\", None) == \"virtual\" and not (dataset.sql or \"\").strip():\n        raise ValueError(\"virtual dataset requires a non-empty sql query\")","typeGuard":"def is_complete_virtual_dataset(dataset: object) -> bool:\n    return not (getattr(dataset, \"kind\", \"\") == \"virtual\" and not (getattr(dataset, \"sql\", None) or \"\").strip())","tryCatchPattern":"from superset.exceptions import SupersetGenericDBErrorException\n\ntry:\n    cols = get_virtual_table_metadata(dataset)\nexcept SupersetGenericDBErrorException as ex:\n    if \"cannot be empty\" in str(ex):\n        raise ValueError(f\"Dataset {dataset.id} is virtual but has no SQL; fix in dataset editor\") from ex\n    raise","preventionTips":["Enforce non-empty sql in dataset creation APIs and import tooling.","Periodically audit: SELECT id FROM tables WHERE kind='virtual' AND (sql IS NULL OR sql='').","Treat empty-SQL virtual datasets as import defects and reject them in CI."],"tags":["virtual-dataset","dataset","metadata","validation"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}