apache/superset · error · SupersetSecurityException

Custom SQL fields cannot be parsed as a single SQL statement

Error message

Custom SQL fields cannot be parsed as a single SQL statement.

What it means

SupersetSecurityException (ADHOC_SUBQUERY_NOT_ALLOWED_ERROR) raised in validate_adhoc_subquery's expression validator (models.py:1004) when a custom SQL expression cannot be parsed by sqlglot as a single statement after wrapping it as SELECT <expr>. Jinja-containing expressions are exempt (skeleton replaces Jinja blocks with NULL), so this fires only for plain SQL that fails parsing — for example unbalanced parentheses or garbage tokens in a metric/column SQL field.

Source

Thrown at superset/connectors/sqla/models.py:1004

    is still inspected; structural attacks smuggled in the non-templated
    portion of an otherwise-templated expression are still rejected.
    Expressions whose substituted skeleton is unparseable (typically due to
    ``{% if %}`` control-flow templating) fall back to deferring validation
    to query time, when the template processor has a real context.
    """
    if not expression:
        return
    skeleton = _JINJA_BLOCK_RE.sub(" NULL ", expression)
    contains_jinja = skeleton != expression
    engine = database.backend
    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,
            )
        )

View on GitHub (pinned to f4587218dd)

Solutions

  1. Fix the expression so it parses as one statement: it must be an expression (not a full query), with balanced parentheses and engine-valid syntax.
  2. Verify the expression alone: wrap mentally in SELECT <expr> and run it against the target database.
  3. If the syntax is valid in your engine but sqlglot rejects it, simplify (e.g. avoid exotic operators) or file/track a sqlglot parsing issue; do not bypass the validator.

Example fix

-- before (adhoc metric SQL)
SUM(CASE WHEN region = 'EMEA' THEN sales

-- after
SUM(CASE WHEN region = 'EMEA' THEN sales ELSE 0 END)
Defensive patterns

Strategy: validation

Validate before calling

from sqlglot import parse_one
from sqlglot.errors import ParseError

def parses_as_single_expression(expr: str) -> bool:
    try:
        parse_one(f"SELECT {expr}")
        return True
    except ParseError:
        return False

Try / catch

from superset.exceptions import SupersetSecurityException

try:
    validate_adhoc_subquery(sql_expr, database, catalog, schema)
except SupersetSecurityException as ex:
    show_user_error("Custom SQL must be a single valid SQL expression")
    raise

Prevention

When it happens

Trigger: Entering a Custom SQL adhoc metric or column whose expression is not a valid single SQL expression (e.g. 'SUM(x' or 'SELECT * FROM t') — set operations and multi-statement input are caught by sibling checks; this one catches pure parse failures of the wrapped SELECT.

Common situations: Typos in the adhoc metric SQL box in Explore; pasting a full query instead of an expression into a metric field; dialect-specific syntax sqlglot cannot parse for the chosen database engine.

Related errors


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