Skip to content

fix(mcp): surface validation errors in generate_chart instead of empty response#39522

Open
EnxDev wants to merge 2 commits intomasterfrom
enxdev/fix/mcp-mixed-timeseries-silent-validation-error
Open

fix(mcp): surface validation errors in generate_chart instead of empty response#39522
EnxDev wants to merge 2 commits intomasterfrom
enxdev/fix/mcp-mixed-timeseries-silent-validation-error

Conversation

@EnxDev
Copy link
Copy Markdown
Contributor

@EnxDev EnxDev commented Apr 21, 2026

SUMMARY

generate_chart with a mixed_timeseries config that used the XY field names kind / kind_secondary (instead of primary_kind / secondary_kind) returned a response with success: false but message: "An error occurred", empty details, and no suggestions — a silent-looking failure for LLM callers.

Root cause: ValidationPipeline.validate_request_with_warnings catches the ValueError raised by parse_chart_config and routes it through ChartErrorBuilder.build_error(template_key="validation_error", ...), but "validation_error" was never registered in ChartErrorBuilder.TEMPLATES. The builder fell back to its hardcoded defaults ("An error occurred", empty details, no suggestions) and the sanitized reason was discarded.

The same code path affects every chart type when parse_chart_config raises inside the pipeline — mixed_timeseries just made it easy to hit because the field-name mismatch is a common LLM miscue.

BEFORE/AFTER

Before

{
  "success": false,
  "error": {
    "error_type": "validation_system_error",
    "message": "An error occurred",
    "details": "",
    "suggestions": [],
    "error_code": "VALIDATION_PIPELINE_ERROR"
  }
}

After

{
  "success": false,
  "error": {
    "error_type": "validation_system_error",
    "message": "Chart configuration is invalid: Value error, Unknown field 'kind'. Valid fields: ... primary_kind ... secondary_kind ...",
    "details": "Value error, Unknown field 'kind'. Valid fields: ... | Unknown field 'kind_secondary' — did you mean 'y_secondary'?",
    "suggestions": [
      "Review the field names and types in your config against the chart_type's schema",
      "Call get_chart_type_schema or read the chart://configs resource for valid fields and examples",
      "For mixed_timeseries charts, use 'primary_kind' and 'secondary_kind' (not 'kind' / 'kind_secondary')"
    ],
    "error_code": "VALIDATION_PIPELINE_ERROR"
  }
} 

TESTING INSTRUCTIONS

run pytest tests/unit_tests/mcp_service/chart/validation/test_pipeline_error_surface.py -v

Run this prompt:

Call the generate_chart MCP tool with these exact arguments:
{ "dataset_id": 3, "config": { "chart_type": "mixed_timeseries", "x": {"name": "order_date"}, "y": [{"name": "revenue", "aggregate": "SUM"}], "y_secondary": [{"name": "order_id", "aggregate": "COUNT"}], "kind": "line", "kind_secondary": "bar" } }
Paste the raw tool response verbatim — do not summarize, do not interpret, do not drop fields.

Before: generic empty error. After: actionable error naming the invalid fields and pointing to primary_kind / secondary_kind.

After: "message":"Chart configuration is invalid: Value error, Unknown field 'kind'. Valid fields: chart_type, dimension, filters, group_by, group_by_secondary, groupby, groupby_b, groupby_secondary, metrics, metrics_b, primary_kind, row_limit,",
"details":"Value error, Unknown field 'kind'. Valid fields: chart_type, dimension, filters, group_by, group_by_secondary, groupby, groupby_b, groupby_secondary, metrics, metrics_b, primary_kind, row_limit"

Known cosmetic follow-up

Template variables are HTML-escaped by _sanitize_user_input so literal
apostrophes render as ' in the JSON. This is pre-existing behavior
across all error templates and out of scope here;

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

`ValidationPipeline.validate_request_with_warnings` catches inner exceptions
from `parse_chart_config` and routes them through
`ChartErrorBuilder.build_error(template_key="validation_error", ...)`, but
that template was never registered in `ChartErrorBuilder.TEMPLATES`. The
builder fell back to its hardcoded `"An error occurred"` message with empty
details and no suggestions — making failures look silent to LLM callers.

The most visible trigger was a `mixed_timeseries` config using the XY field
names `kind` / `kind_secondary` instead of `primary_kind` / `secondary_kind`:
the Pydantic ValueError was caught, then rendered as a blank error.

- Add the missing `validation_error` template so the sanitized reason lands
  in the response message, details, and suggestions.
- Strip Pydantic's `tagged-union[...]` header and `errors.pydantic.dev`
  footer in `_sanitize_validation_error` so the 200-char truncation doesn't
  swallow the actionable `Value error, Unknown field ...` body.
- Add regression tests covering the template presence, the mixed_timeseries
  wrong-field-name case, and a positive control.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bito-code-review
Copy link
Copy Markdown
Contributor

bito-code-review Bot commented Apr 21, 2026

Code Review Agent Run #7d4795

Actionable Suggestions - 0
Review Details
  • Files reviewed - 3 · Commit Range: 2054487..2054487
    • superset/mcp_service/chart/validation/pipeline.py
    • superset/mcp_service/utils/error_builder.py
    • tests/unit_tests/mcp_service/chart/validation/test_pipeline_error_surface.py
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@dosubot dosubot Bot added the change:backend Requires changing the backend label Apr 21, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 21, 2026

Codecov Report

❌ Patch coverage is 0% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.52%. Comparing base (151d7d7) to head (a850bf7).
⚠️ Report is 33 commits behind head on master.

Files with missing lines Patch % Lines
superset/mcp_service/chart/validation/pipeline.py 0.00% 8 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #39522      +/-   ##
==========================================
+ Coverage   64.44%   64.52%   +0.07%     
==========================================
  Files        2560     2562       +2     
  Lines      133574   133413     -161     
  Branches    31017    30986      -31     
==========================================
- Hits        86082    86081       -1     
+ Misses      45999    45840     -159     
+ Partials     1493     1492       -1     
Flag Coverage Δ
hive 39.86% <0.00%> (+0.10%) ⬆️
mysql 60.43% <0.00%> (+0.16%) ⬆️
postgres 60.51% <0.00%> (+0.16%) ⬆️
presto 41.64% <0.00%> (+0.11%) ⬆️
python 62.08% <0.00%> (+0.16%) ⬆️
sqlite 60.14% <0.00%> (+0.16%) ⬆️
unit 100.00% <ø> (ø)

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

☔ View full report in Codecov by Sentry.
📢 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.

Comment thread superset/mcp_service/chart/validation/pipeline.py Outdated
Comment thread superset/mcp_service/utils/error_builder.py Outdated
EnxDev added a commit that referenced this pull request Apr 21, 2026
Addresses review feedback on #39522:

1. ``_sanitize_validation_error`` only stripped the Pydantic
   ``tagged-union[...]`` header when the body began with ``Value error,``.
   Other common Pydantic failure bodies — ``Input should be ...`` from
   literal enums, ``String should match pattern ...``, etc. — still kept
   the long header and got truncated before the actionable part. Match the
   first two-space-indented body line instead, which is Pydantic's
   universal separator between the tagged-union header and the per-field
   message. Works for every body style without a keyword allowlist.

2. The ``validation_error`` template fires for every chart type, so the
   ``primary_kind`` / ``secondary_kind`` suggestion was misleading for
   non-mixed_timeseries failures. Replace it with chart-type-agnostic
   guidance that points callers at the valid-fields list already rendered
   in the error details.

Add regression tests for the non-``Value error`` body case (invalid
aggregate enum on a pie chart) and for the suggestion's chart-type
agnosticism.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bito-code-review
Copy link
Copy Markdown
Contributor

bito-code-review Bot commented Apr 21, 2026

Code Review Agent Run #1dccb1

Actionable Suggestions - 0
Additional Suggestions - 1
  • superset/mcp_service/utils/error_builder.py - 1
    • Misleading error suggestion · Line 197-198
      The new suggestion assumes error details list valid field names, but validation errors like 'unexpected field' don't provide such lists, potentially confusing users. Consider a more general suggestion.
      Code suggestion
       @@ -197,2 +197,2 @@
      -                "Replace any unknown field names with the ones listed in the "
      -                "error details above",
      +                "Refer to the error details for specific validation issues and "
      +                "correct them",
Review Details
  • Files reviewed - 3 · Commit Range: 2054487..ebb3dd4
    • superset/mcp_service/chart/validation/pipeline.py
    • superset/mcp_service/utils/error_builder.py
    • tests/unit_tests/mcp_service/chart/validation/test_pipeline_error_surface.py
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Copy link
Copy Markdown
Member

@msyavuz msyavuz left a comment

Choose a reason for hiding this comment

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

LGTM with a small nit


def _sanitize_validation_error(error: Exception) -> str:
"""SECURITY FIX: Sanitize validation errors to prevent disclosure."""
import re
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this be a module level import? I think this function level imports is the pattern in this file though so not sure

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

good point, I'm going to move it on the top as a standard Python convention

Copy link
Copy Markdown
Contributor

@alexandrusoare alexandrusoare left a comment

Choose a reason for hiding this comment

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

LGTM just a nit

# below doesn't swallow the actionable part. The pydantic footer
# ``\n For further information ...`` uses four-space indent and
# is dropped here.
if "tagged-union[" in error_str:
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.

Is this string a constant, and if it is maybe we should give it to a variable?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch, replaced!

Addresses review feedback on #39522:

1. ``_sanitize_validation_error`` only stripped the Pydantic
   ``tagged-union[...]`` header when the body began with ``Value error,``.
   Other common Pydantic failure bodies — ``Input should be ...`` from
   literal enums, ``String should match pattern ...``, etc. — still kept
   the long header and got truncated before the actionable part. Match the
   first two-space-indented body line instead, which is Pydantic's
   universal separator between the tagged-union header and the per-field
   message. Works for every body style without a keyword allowlist.

2. The ``validation_error`` template fires for every chart type, so the
   ``primary_kind`` / ``secondary_kind`` suggestion was misleading for
   non-mixed_timeseries failures. Replace it with chart-type-agnostic
   guidance that points callers at the valid-fields list already rendered
   in the error details.

Add regression tests for the non-``Value error`` body case (invalid
aggregate enum on a pie chart) and for the suggestion's chart-type
agnosticism.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@EnxDev EnxDev force-pushed the enxdev/fix/mcp-mixed-timeseries-silent-validation-error branch from ebb3dd4 to a850bf7 Compare April 22, 2026 12:18
@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 22, 2026

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit a850bf7
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/69e8bc81088f1e0008f9c7a4
😎 Deploy Preview https://deploy-preview-39522--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

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

@bito-code-review
Copy link
Copy Markdown
Contributor

bito-code-review Bot commented Apr 22, 2026

Code Review Agent Run #c397dd

Actionable Suggestions - 0
Review Details
  • Files reviewed - 3 · Commit Range: 2054487..a850bf7
    • superset/mcp_service/chart/validation/pipeline.py
    • superset/mcp_service/utils/error_builder.py
    • tests/unit_tests/mcp_service/chart/validation/test_pipeline_error_surface.py
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@EnxDev EnxDev added the hold:testing! On hold for testing label Apr 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:backend Requires changing the backend hold:testing! On hold for testing size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants