apache/superset · error · QueryObjectValidationError

The following entries in `series_columns` are missing in `co

Error message

The following entries in `series_columns` are missing in `columns`: %(columns)s. 

What it means

QueryObjectValidationError raised by QueryObject._validate_there_are_no_missing_series when one or more names listed in series_columns do not appear in the query object's columns list. Superset requires every series (groupby/dimension used for series limiting or sequencing) to also be part of the selected columns so the generated SQL can actually project them. It is a client-side consistency check that fires before any SQL is issued.

Source

Thrown at superset/common/query_object.py:386

                        # source_engine=engine ensures idempotency: this
                        # method can run more than once (validate() is called
                        # from both raise_for_access and get_df_payload), so
                        # the second pass must be able to re-parse the
                        # dialect-specific output (e.g. BigQuery backticks)
                        # produced by the first pass.
                        clause = transpile_to_dialect(
                            clause, engine, source_engine=engine, identify=True
                        )

                    sanitized_clause = sanitize_clause(clause, engine)
                    self.extras[param] = sanitized_clause
                except QueryClauseValidationException as ex:
                    raise QueryObjectValidationError(ex.message) from ex

    def _validate_there_are_no_missing_series(self) -> None:
        missing_series = [col for col in self.series_columns if col not in self.columns]
        if missing_series:
            raise QueryObjectValidationError(
                _(
                    "The following entries in `series_columns` are missing "
                    "in `columns`: %(columns)s. ",
                    columns=", ".join(f'"{x}"' for x in missing_series),
                )
            )

    def to_dict(self) -> QueryObjectDict:
        query_object_dict: QueryObjectDict = {
            "apply_fetch_values_predicate": self.apply_fetch_values_predicate,
            "columns": self.columns,
            "extras": self.extras,
            "filter": self.filter,
            "from_dttm": self.from_dttm,
            "granularity": self.granularity,
            "inner_from_dttm": self.inner_from_dttm,
            "inner_to_dttm": self.inner_to_dttm,
            "is_rowcount": self.is_rowcount,

View on GitHub (pinned to f4587218dd)

Solutions

  1. Inspect the query payload and add every missing series_columns entry to the columns (groupby) list of the same query object.
  2. If the series column no longer exists in the dataset, remove or rename it in series_columns to match the current dataset schema.
  3. For chart plugins, ensure the transformFormData logic copies the same field into both groupby and series_columns.
  4. Run the query through /api/v1/chart/data with a minimal payload after fixing to confirm validation passes.

Example fix

// before
const queryObject = {
  columns: ['country'],
  series_columns: ['country', 'region'], // 'region' missing from columns
  metrics: ['sum__sales'],
};

// after
const queryObject = {
  columns: ['country', 'region'], // every series column is projected
  series_columns: ['country', 'region'],
  metrics: ['sum__sales'],
};
Defensive patterns

Strategy: validation

Validate before calling

def validate_series_in_columns(query_object: dict) -> None:
    columns = set(query_object.get("columns") or [])
    missing = [c for c in (query_object.get("series_columns") or []) if c not in columns]
    if missing:
        raise ValueError(f"series_columns not in columns: {missing}")

Try / catch

from superset.common.query_object import QueryObject
from superset.exceptions import QueryObjectValidationError

try:
    qo = QueryObject(**params)
except QueryObjectValidationError as ex:
    if "series_columns" in str(ex):
        params["columns"] = list(set(params.get("columns", [])) | set(params.get("series_columns", [])))
        qo = QueryObject(**params)
    else:
        raise

Prevention

When it happens

Trigger: Building a QueryContext/QueryObject payload (e.g. via chart REST API /api/v1/chart/data or programmatically via superset.common.QueryObject) where series_columns contains a column name that is absent from columns. Typical with custom chart plugins or hand-crafted FormData that set series_columns independently of groupby/columns.

Common situations: Custom viz plugins that add series_columns without mirroring them into groupby; renames of a dataset column where the chart definition still stores the old name in series metadata; programmatic query generation that derives series_columns from a different source than columns.

Related errors


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