You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by el...@apache.org on 2026/09/12 15:11:21 UTC
(superset) 01/01: fix(sql-validate): downgrade log level for undefined Jinja function errors (SC-120409)
This is an automated email from the ASF dual-hosted git repository.
eschutho pushed a commit to branch fix-undefined-ref-validate-sql-log-level
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 438258c7b0ca19c23bd2298b745110c1e7c507aa
Author: Elizabeth Thompson <es...@gmail.com>
AuthorDate: Sat Sep 12 15:11:06 2026 +0000
fix(sql-validate): downgrade log level for undefined Jinja function errors (SC-120409)
UndefinedTemplateFunctionException is a subclass of SupersetTemplateException,
so in ValidateSQLCommand.run() it fell into the generic template-exception
branch and was logged at ERROR with a full traceback — even though it already
returns a clean 400 to the client. This is a user input mistake (e.g. calling a
dbt-style ref() macro Superset does not provide), not a system fault, and is the
sole source of Sentry noise for SUPERSET-PYTHON-ZY6 (204+ events).
Add a dedicated except-clause before the SupersetTemplateException branch that
logs at WARNING without a traceback (mirroring the sibling
SupersetSyntaxErrorException branch and the SQL Lab execute path in
SqlQueryRenderImpl.render, which treats this exception as expected). The
client-facing response is unchanged — only server log severity changes.
Fixes SUPERSET-PYTHON-ZY6
Co-Authored-By: Claude Opus 4.8 <no...@anthropic.com>
---
superset/commands/database/validate_sql.py | 24 ++++++++++-
.../commands/databases/validate_sql_test.py | 50 ++++++++++++++++++++++
2 files changed, 73 insertions(+), 1 deletion(-)
diff --git a/superset/commands/database/validate_sql.py b/superset/commands/database/validate_sql.py
index 17de0062b20..cabee254122 100644
--- a/superset/commands/database/validate_sql.py
+++ b/superset/commands/database/validate_sql.py
@@ -37,7 +37,10 @@ from superset.exceptions import (
SupersetSyntaxErrorException,
SupersetTemplateException,
)
-from superset.jinja_context import get_template_processor
+from superset.jinja_context import (
+ get_template_processor,
+ UndefinedTemplateFunctionException,
+)
from superset.models.core import Database
from superset.sql_validators import get_validator_by_name
from superset.sql_validators.base import BaseSQLValidator
@@ -110,6 +113,25 @@ class ValidateSQLCommand(BaseCommand):
extra={"errors": [err.message for err in ex.errors]},
)
raise ValidatorSQL400Error(ex.errors[0]) from ex
+ except UndefinedTemplateFunctionException as ex:
+ # The user referenced an undefined Jinja function (e.g. a dbt-style
+ # `ref(...)` macro Superset does not provide). This is a user input
+ # mistake, not a system fault, so log at WARNING without a traceback
+ # (mirrors the SupersetSyntaxErrorException branch above and the SQL
+ # Lab execute path in SqlQueryRenderImpl.render). The client-facing
+ # response is unchanged from the generic template-exception branch.
+ logger.warning(
+ "Undefined template function during SQL validation: %s", str(ex)
+ )
+ superset_error = SupersetError(
+ message=__(
+ "Template processing failed: %(ex)s",
+ ex=str(ex),
+ ),
+ error_type=SupersetErrorType.GENERIC_COMMAND_ERROR,
+ level=ErrorLevel.ERROR,
+ )
+ raise ValidatorSQL400Error(superset_error) from ex
except SupersetTemplateException as ex:
# Internal template processing errors (e.g., recursion, unexpected failures)
logger.error(
diff --git a/tests/unit_tests/commands/databases/validate_sql_test.py b/tests/unit_tests/commands/databases/validate_sql_test.py
index 247dfc64654..79def851bc1 100644
--- a/tests/unit_tests/commands/databases/validate_sql_test.py
+++ b/tests/unit_tests/commands/databases/validate_sql_test.py
@@ -31,6 +31,7 @@ from superset.exceptions import (
SupersetSyntaxErrorException,
SupersetTemplateException,
)
+from superset.jinja_context import UndefinedTemplateFunctionException
@pytest.fixture
@@ -251,6 +252,55 @@ def test_validate_sql_template_processing_error(
mock_validator.validate.assert_not_called()
+def test_validate_sql_undefined_template_function(
+ mock_database: MagicMock,
+ mock_validator: MagicMock,
+ mock_template_processor: MagicMock,
+ mock_config: dict[str, Any],
+ mocker: MockerFixture,
+) -> None:
+ """
+ Test that an undefined Jinja function is logged at WARNING, not ERROR.
+
+ UndefinedTemplateFunctionException is a subclass of SupersetTemplateException
+ raised when the user references an undefined Jinja function (e.g. a dbt-style
+ `ref(...)` macro). This is a user input mistake, not a system fault, so it
+ must be logged at WARNING without a traceback while still surfacing the same
+ ValidatorSQL400Error to the client. Prior to the fix it fell into the generic
+ SupersetTemplateException branch and was logged at ERROR with exc_info.
+ """
+ logger_warning = mocker.patch(
+ "superset.commands.database.validate_sql.logger.warning"
+ )
+ logger_error = mocker.patch("superset.commands.database.validate_sql.logger.error")
+
+ mock_template_processor.process_template.side_effect = (
+ UndefinedTemplateFunctionException("'ref' is undefined")
+ )
+
+ data = {
+ "sql": "SELECT * FROM {{ ref('my_model') }} LIMIT 100",
+ "schema": "public",
+ "template_params": {},
+ }
+ command = ValidateSQLCommand(model_id=1, data=data)
+
+ with pytest.raises(ValidatorSQL400Error) as exc_info:
+ command.run()
+
+ error = exc_info.value
+ assert error.error.message is not None
+ assert "Template processing failed" in error.error.message
+ assert "'ref' is undefined" in error.error.message
+ mock_validator.validate.assert_not_called()
+
+ # The whole point of the fix: log at WARNING (no traceback), not ERROR.
+ logger_warning.assert_called_once()
+ logger_error.assert_not_called()
+ # No exc_info=True passed to the warning call (no full traceback).
+ assert "exc_info" not in logger_warning.call_args.kwargs
+
+
def test_validate_sql_generic_exception(
mock_database: MagicMock,
mock_validator: MagicMock,