apache/superset · error · ValidatorSQLUnexpectedError
An unexpected error occurred
Error message
An unexpected error occurred
What it means
ValidatorSQLUnexpectedError (HTTP 422, message 'An unexpected error occurred') is raised at the top of ValidatorSQLCommand.run() when the command's invariants are broken: after validate() has run, either self._validator or self._model is None. Under normal operation validate() would already have raised DatabaseNotFoundError, NoValidatorConfigFoundError, or NoValidatorFoundError, so reaching run() with either field unset indicates an internal state or subclassing bug rather than a user input problem.
Source
Thrown at superset/commands/database/validate_sql.py:67
class ValidateSQLCommand(BaseCommand):
def __init__(self, model_id: int, data: dict[str, Any]):
self._properties = data.copy()
self._model_id = model_id
self._model: Optional[Database] = None
self._validator: Optional[type[BaseSQLValidator]] = None
def run(self) -> list[dict[str, Any]]:
"""
Validates a SQL statement
:return: A List of SQLValidationAnnotation
:raises: DatabaseNotFoundError, NoValidatorConfigFoundError
NoValidatorFoundError, ValidatorSQLUnexpectedError, ValidatorSQLError
ValidatorSQL400Error
"""
self.validate()
if not self._validator or not self._model:
raise ValidatorSQLUnexpectedError()
sql = self._properties["sql"]
catalog = self._properties.get("catalog")
schema = self._properties.get("schema")
template_params = self._properties.get("template_params") or {}
# Check access before rendering the Jinja template (mirrors the SQL
# Lab execute path).
security_manager.raise_for_access(
database=self._model,
sql=sql,
catalog=catalog,
schema=schema,
template_params=template_params,
force_dataset_match=True,
)
try:
# Render Jinja templates to handle template syntax beforeView on GitHub (pinned to f4587218dd)
Solutions
- If you subclass ValidatorSQLCommand, call super().validate() (or replicate its model+validator lookup) so _model and _validator are populated before run().
- If invoking the command programmatically, always call command.validate() before command.run(), or use the REST endpoint which does this for you.
- Verify the database id still exists (DatabaseDAO.find_by_id) if you suspect concurrent deletion, then retry with a valid database_id.
- Check logs for the preceding DatabaseNotFound/NoValidator errors — an unexpected error here usually masks an earlier swallowed exception.
Example fix
// before
cmd = ValidatorSQLCommand(model_id=1, properties={"sql": "SELECT 1"})
cmd.run() # ValidatorSQLUnexpectedError: validate() never ran
// after
cmd = ValidatorSQLCommand(model_id=1, properties={"sql": "SELECT 1"})
cmd.validate() # raises the precise error if db/validator missing
cmd.run() Defensive patterns
Strategy: validation
Validate before calling
# Before invoking the command, confirm both preconditions it asserts
from superset.databases.dao import DatabaseDAO
from superset.sql_validators import get_validator_by_name
from flask import current_app
def can_validate(database_id: int) -> bool:
model = DatabaseDAO.find_by_id(database_id)
if model is None:
return False
by_engine = current_app.config["SQL_VALIDATORS_BY_ENGINE"]
name = by_engine.get(model.db_engine_spec.engine)
return name is not None and get_validator_by_name(name) is not None Try / catch
from superset.commands.database.exceptions import ValidatorSQLUnexpectedError
try:
cmd = ValidatorSQLCommand(model_id, properties)
cmd.validate()
cmd.run()
except ValidatorSQLUnexpectedError:
# invariant break: log state (validator, model id) and fail loudly — do not mask as user error
logger.exception("validate_sql invariant broken", extra={"model_id": model_id})
raise Prevention
- Never call command.run() without command.validate() when using command classes directly.
- In subclasses, always call super().validate() so _model and _validator are populated.
- Treat this error as a bug report, not an input error — capture a traceback in monitoring.
When it happens
Trigger: Calling run() on a ValidatorSQLCommand whose validate() was skipped or overridden to a no-op; subclassing the command and not populating _model/_validator; a race where the validator registry or database row disappears between validate() and run() (e.g., concurrent deletion of the Database row).
Common situations: Custom subclasses of the validate_sql command that override validate() without calling super(); calling the internal command API directly (not via the REST endpoint) in scripts/tests without invoking validate() first; code upgrades that changed the command lifecycle.
Related errors
- ex.errors[0]
- Template processing failed: %(ex)s
- %(validator)s was unable to check your query. Please recheck
- Database not found.
- no SQL validator is configured for %(engine_spec)s
AI-assisted analysis of apache/superset@f4587218dd (2026-08-14).
Data as JSON: /api/errors/687d4169a1cc629d.
Report an issue: GitHub.