apache/superset · error · SupersetSecurityException
Custom SQL fields cannot contain set operations.
Error message
Custom SQL fields cannot contain set operations.
What it means
SupersetSecurityException (ADHOC_SUBQUERY_NOT_ALLOWED_ERROR) raised in validate_adhoc_subquery (models.py:1015) when sqlglot's is_set_operation() reports that the wrapped expression contains a set operation (UNION/INTERSECT/EXCEPT [ALL]). Custom SQL fields for metrics/columns/filters must be single scalar expressions; set operations would allow smuggling subquery-like behavior, so Superset blocks them outright.
Source
Thrown at superset/connectors/sqla/models.py:1015
wrapped = f"SELECT {skeleton}"
try:
parsed = SQLStatement(wrapped, engine)
except SupersetParseError as ex:
if contains_jinja:
return
raise SupersetSecurityException(
SupersetError(
error_type=SupersetErrorType.ADHOC_SUBQUERY_NOT_ALLOWED_ERROR,
message=_(
"Custom SQL fields cannot be parsed as a single SQL statement."
),
level=ErrorLevel.ERROR,
)
) from ex
if parsed.is_set_operation():
raise SupersetSecurityException(
SupersetError(
error_type=SupersetErrorType.ADHOC_SUBQUERY_NOT_ALLOWED_ERROR,
message=_("Custom SQL fields cannot contain set operations."),
level=ErrorLevel.ERROR,
)
)
validate_adhoc_subquery(
wrapped,
database,
catalog,
schema or "",
engine,
)
sanitize_clause(wrapped, engine)
class TableColumn(AuditMixinNullable, ImportExportMixin, CertificationMixin, Model):View on GitHub (pinned to f4587218dd)
Solutions
- Remove the set operation from the custom SQL field; compute the unioned data in a virtual dataset (its SQL supports full queries) and reference that dataset instead.
- Restructure the metric as a single expression, e.g. use SUM/CASE aggregation over joined rows rather than UNION.
- If you genuinely need set-operation SQL, put it in the dataset's virtual SQL or a derived view in the database, not in an adhoc field.
Example fix
-- before (adhoc metric SQL — rejected) SELECT SUM(a) FROM t1 UNION SELECT SUM(b) FROM t2 -- after -- create a virtual dataset with the union, then use a simple metric on it SUM(value) -- on dataset: SELECT a AS value FROM t1 UNION ALL SELECT b FROM t1
Defensive patterns
Strategy: validation
Validate before calling
from superset.db_engine_specs.presto import SQLStatement # illustrative
from sqlglot import parse_one
def contains_set_operation(expr: str) -> bool:
tree = parse_one(f"SELECT {expr}")
return any(node.key in {"union", "intersect", "except", "union_all", "union_distinct"} for node in tree.walk()) Try / catch
from superset.exceptions import SupersetSecurityException
try:
validate_adhoc_subquery(expr, database, catalog, schema)
except SupersetSecurityException as ex:
if "set operations" in str(ex):
guide_user_to_virtual_dataset()
raise Prevention
- Never put UNION/INTERSECT/EXCEPT in adhoc fields; move that SQL into a virtual dataset.
- Teach users the distinction: adhoc field = scalar expression, virtual dataset = full query.
- CI-lint stored expressions for set-operation tokens.
When it happens
Trigger: Putting e.g. 'SELECT a FROM t UNION SELECT b FROM t2' or an expression whose parse tree contains UNION/INTERSECT/EXCEPT into a Custom SQL metric, column, or filter value field in Explore or the dataset editor.
Common situations: Users pasting union-based queries into adhoc metric SQL; attempts to simulate subqueries via set operators; Jinja that renders to SQL containing UNION (Jinja skeletons replace {% %}/{{ }} blocks, but fully rendered UNIONs are caught).
Related errors
- Custom SQL fields cannot be parsed as a single SQL statement
- Adhoc metric aggregate is invalid
- Adhoc metric SQL expression is invalid
- Adhoc metric expressionType is invalid
- Only `SELECT` statements are allowed
AI-assisted analysis of apache/superset@f4587218dd (2026-08-14).
Data as JSON: /api/errors/decf3589a147e7bc.
Report an issue: GitHub.