apache/superset · error · SupersetGenericDBErrorException

Virtual dataset query cannot be empty

Error message

Virtual dataset query cannot be empty

What it means

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.

Source

Thrown at superset/connectors/sqla/utils.py:109

            col.update(
                {
                    "type": "UNKNOWN",
                    "type_generic": None,
                    "is_dttm": None,
                }
            )
    return cols


def _has_jinja_markers(sql: str) -> bool:
    """Return True if ``sql`` contains Jinja template markers (``{%`` or ``{{``)."""
    return "{%" in sql or "{{" in sql


def get_virtual_table_metadata(dataset: SqlaTable) -> list[ResultSetColumnType]:
    """Use SQLparser to get virtual dataset metadata"""
    if not dataset.sql:
        raise SupersetGenericDBErrorException(
            message=_("Virtual dataset query cannot be empty"),
        )

    db_engine_spec = dataset.database.db_engine_spec
    original_sql = dataset.sql
    try:
        sql = dataset.get_template_processor().process_template(
            original_sql, **dataset.template_params_dict
        )
    except SupersetSyntaxErrorException as ex:
        # ``process_template`` aggregates several jinja2 exceptions
        # (``TemplateSyntaxError``, ``SecurityError``, ``UndefinedError``,
        # ``Unicode*Error``) into ``SupersetSyntaxErrorException``. Only
        # the ``UndefinedError`` case is a "missing runtime context"
        # signal that ``RefreshDatasetCommand`` can safely soften — the
        # rest (sandbox violations, malformed template syntax, encoding
        # errors) indicate a real problem with the template that must
        # surface. See #38012.

View on GitHub (pinned to f4587218dd)

Solutions

  1. Open the dataset in the editor and provide the virtual dataset's SQL query, then save.
  2. 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.
  3. Audit for other broken rows: SELECT id, table_name FROM tables WHERE kind='virtual' AND (sql IS NULL OR sql='');

Example fix

# before
Dataset(kind='virtual', table_name='my_vds', sql=None)

# after
Dataset(kind='virtual', table_name='my_vds', sql='SELECT id, amt FROM sales WHERE amt > 0')
Defensive patterns

Strategy: validation

Validate before calling

def validate_virtual_dataset(dataset) -> None:
    if getattr(dataset, "kind", None) == "virtual" and not (dataset.sql or "").strip():
        raise ValueError("virtual dataset requires a non-empty sql query")

Type guard

def is_complete_virtual_dataset(dataset: object) -> bool:
    return not (getattr(dataset, "kind", "") == "virtual" and not (getattr(dataset, "sql", None) or "").strip())

Try / catch

from superset.exceptions import SupersetGenericDBErrorException

try:
    cols = get_virtual_table_metadata(dataset)
except SupersetGenericDBErrorException as ex:
    if "cannot be empty" in str(ex):
        raise ValueError(f"Dataset {dataset.id} is virtual but has no SQL; fix in dataset editor") from ex
    raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of apache/superset@f4587218dd (2026-08-14). Data as JSON: /api/errors/742129a05d5f85eb. Report an issue: GitHub.