Skip to content

fix(sqla): raise QueryObjectValidationError for template errors in adhoc column metadata lookup - #45742

Merged
eschutho merged 2 commits into
apache:masterfrom
eschutho:fix-adhoc-column-undefinederror-metadata-lookup
Oct 27, 2026
Merged

eschutho merged 2 commits into
apache:masterfrom
eschutho:fix-adhoc-column-undefinederror-metadata-lookup

Conversation

@eschutho

Copy link
Copy Markdown
Member

SUMMARY

Problem. SqlaTable._render_adhoc_expression_for_metadata_lookup renders Jinja in an adhoc column's sqlExpression before the metadata lookup, but only caught SupersetSyntaxErrorException. BaseTemplateProcessor.process_template re-raises a raw jinja2.exceptions.UndefinedError when the undefined name isn't shaped like a function call (e.g. {{ foo.bar }}). That error escaped adhoc_column_to_sqla, was not handled by the chart-data API (which only maps QueryObjectValidationError to a 400), and fell through to the catch-all Exception handler as an opaque 500.

Fix. Catch (TemplateError, SupersetSyntaxErrorException) and raise QueryObjectValidationError with the existing message text (unchanged). UndefinedError subclasses TemplateError. This matches how sibling sites in the same file already behave (the except UndefinedError / except (TemplateError, SupersetSyntaxErrorException) handlers). Only this one site is changed.

Same bug class as #42366 and #42401.

Behavior change. A template error in an adhoc column expression now returns a 400 with a validation message instead of a raw 500. The catch is additive; no previously handled path changes.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

N/A

TESTING INSTRUCTIONS

Added test_adhoc_column_to_sqla_wraps_undefined_error_in_metadata_lookup in tests/unit_tests/connectors/sqla/models_test.py. It uses a real JinjaTemplateProcessor and an adhoc column with sqlExpression="{{ foo.bar }}", and asserts QueryObjectValidationError. Before the fix it fails with jinja2.exceptions.UndefinedError: 'foo' is undefined; after, it passes.

pytest tests/unit_tests/connectors/sqla/models_test.py -k wraps_undefined_error_in_metadata

Manual: POST a chart-data request with an adhoc column whose sqlExpression is {{ foo.bar }}; expect a 400 rather than a 500.

Notes on verification:

  • That chart-data requests reach SqlaTable.adhoc_column_to_sqla (which overrides the ExploreMixin one) was confirmed by reading the code, not by a live request.
  • tests/unit_tests/connectors/sqla/models_test.py has 6 unrelated failures that also occur without this change (cross-catalog table quoting: test_get_sqla_table_*, test_quoted_name_prevents_double_quoting).

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

🤖 Generated with Claude Code

…hoc column metadata lookup

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@codeant-ai-for-open-source

codeant-ai-for-open-source Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

CodeAnt  CodeAnt PR Risk

🟢  Low Risk

  • The PR appears safe to merge; no actionable issues were identified in the review.

Assessed commit: 194bfefe690c

@codecov

codecov Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 84.33%. Comparing base (09207d9) to head (194bfef).
⚠️ Report is 19 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #45742      +/-   ##
==========================================
+ Coverage   84.31%   84.33%   +0.01%     
==========================================
  Files        3059     3059              
  Lines      202225   202267      +42     
  Branches    47367    47373       +6     
==========================================
+ Hits       170516   170574      +58     
+ Misses      28451    28435      -16     
  Partials     3258     3258              
Flag Coverage Δ
hive 34.77% <0.00%> (-0.01%) ⬇️
mysql 52.80% <0.00%> (-0.02%) ⬇️
postgres 52.81% <0.00%> (-0.02%) ⬇️
presto 36.50% <0.00%> (-0.01%) ⬇️
python 87.46% <100.00%> (+0.01%) ⬆️
sqlite 52.57% <0.00%> (-0.02%) ⬇️
unit 81.98% <100.00%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@rebenitez1802 rebenitez1802 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for the fix. Verified the new test fails on master with a raw UndefinedError and passes here. One non-blocking note inline.

try:
return template_processor.process_template(sql_expression)
except SupersetSyntaxErrorException as ex:
except (TemplateError, SupersetSyntaxErrorException) as ex:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium: same 500 still reachable via adhoc metrics / metric orderby (OK as a follow-up)

This fixes adhoc columns, and adhoc filters whose col is an adhoc SQL column. A {{ foo.bar }} in an adhoc SQL metric, or in an orderby on one, still returns a 500 from /api/v1/chart/data. Two places are affected:

  • SqlaTable.adhoc_metric_to_sqla (models.py:2349-2357) only catches SupersetSecurityException.
  • _process_metric_orderby_expression in superset/models/helpers.py (~L5110) has no template-error handling.

That code is outside this diff, so I can't attach an applyable suggestion. Something like this in adhoc_metric_to_sqla would close the metric case. It reuses the existing "metric expression" msgid, so .pot won't drift:

            if not processed:
                try:
                    expression = self._process_metric_select_expression(
                        expression=expression,
                        engine=self.database.backend,
                        schema=self.schema,
                        template_processor=template_processor,
                    )
                except SupersetSecurityException as ex:
                    raise QueryObjectValidationError(ex.message) from ex
                except (TemplateError, SupersetSyntaxErrorException) as ex:
                    raise QueryObjectValidationError(
                        _(
                            "Error in jinja expression in metric expression: %(msg)s",
                            msg=str(ex),
                        )
                    ) from ex

The orderby path in helpers.py would need the same wrapping. Not blocking: happy to see this in this PR or in a follow-up.

…fy mypy

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@netlify

netlify Bot commented Oct 26, 2026

Copy link
Copy Markdown

✅ Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit 194bfef
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6adfcdeb67ff7d779c8b30a8
😎 Deploy Preview https://deploy-preview-45742--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@eschutho
eschutho merged commit 74ec704 into apache:master Oct 27, 2026
73 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants