DanRoscigno opened a new issue, #42626:
URL: https://github.com/apache/superset/issues/42626

   ### Bug
   
   `superset/mcp_service/chart/schemas.py` defines `UnknownFieldCheckMixin` to 
stop unknown fields from being silently dropped:
   
   ```python
   def _check_unknown_fields(data: Any, model_class: type[BaseModel]) -> Any:
       """Raise ValueError for unrecognized fields with 'did you mean?' 
suggestions.
   
       Catches fields that would be silently dropped by extra='ignore' and 
provides
       actionable error messages to help LLMs self-correct parameter names.
       """
   ```
   
   All ten top-level chart config models inherit it — `PieChartConfig`, 
`PivotTableChartConfig`, `MixedTimeseriesChartConfig`, `HandlebarsChartConfig`, 
`BigNumberChartConfig`, `TableChartConfig`, `XYChartConfig`, 
`HistogramChartConfig`, `BoxPlotChartConfig`, `WaterfallChartConfig`.
   
   The nested models those configs are composed of do not:
   
   | Model | Line (master @ `7b351d5`) | Base |
   |---|---|---|
   | `ColumnRef` | 774 | `BaseModel` |
   | `AxisConfig` | 895 | `BaseModel` |
   | `LegendConfig` | 901 | `BaseModel` |
   | `CurrencyFormat` | 906 | `BaseModel` |
   | `FilterConfig` | 929 | `BaseModel` |
   | `SortByConfig` | 997 | `BaseModel` |
   
   So pydantic's default `extra="ignore"` applies one level down, and 
unknown-field protection is enforced at exactly one level of nesting.
   
   ### Reproduction
   
   ```python
   from superset.mcp_service.chart.schemas import parse_chart_config
   
   base = {"chart_type": "xy", "kind": "bar",
           "x": {"name": "state"}, "y": [{"name": "orders", "aggregate": 
"SUM"}]}
   
   # unknown field NESTED inside x_axis
   cfg = parse_chart_config({**base, "x_axis": {"title": "State", "sort_by": 
"metric"}})
   print(cfg.x_axis)
   
   # the same unknown field at TOP level
   parse_chart_config({**base, "sort_by": "metric"})
   ```
   
   Output:
   
   ```
   AxisConfig(title='State', scale='linear', format=None)     # sort_by 
silently gone
   ValueError: 1 validation error for tagged-union[...]
   xy
     Value error, Unknown field 'sort_by'. Valid fields: breakdown, chart_type, 
...
   ```
   
   Same asymmetry through the MCP tools. Against a saved bar chart, 
`update_chart` with an unknown field nested in `x_axis`, `x`, or `legend` 
returns `success: true` and a chart URL:
   
   ```json
   {"chart": {"id": 1, "slice_name": "Orders by Customer State", ...},
    "success": true, "error": null, "warnings": []}
   ```
   
   while a subsequent `get_chart_info` shows the stored `form_data` unchanged:
   
   ```json
   "x_axis_sort_series_type": "name", "x_axis_sort_series_ascending": true
   ```
   
   The same field at the top level of `config` is correctly rejected with the 
"Valid fields:" list.
   
   ### Impact
   
   The mixin exists specifically so that LLM clients get an actionable error 
instead of a silent drop. Nested objects are where axis, legend, currency and 
filter options live — precisely the options a client is most likely to guess 
at, and the ones least likely to be memorised correctly.
   
   The failure mode is worse than a plain rejection. The tool returns `success: 
true` with a chart URL and no warnings, so the caller reasonably concludes the 
setting was applied. Detecting otherwise requires a follow-up `get_chart_info` 
*and* knowing which native `form_data` key the config field maps to. An agent 
that self-corrects on error has nothing to correct against, so it moves on 
believing the chart is configured.
   
   Encountered while trying to sort a bar chart by value via `x_axis: 
{"sort_by": "metric"}`: three successive `update_chart` calls each returned 
success and changed nothing.
   
   ### Suggested fix
   
   Have the nested models inherit `UnknownFieldCheckMixin` instead of 
`BaseModel`:
   
   ```python
   class AxisConfig(UnknownFieldCheckMixin):
       ...
   ```
   
   `_check_unknown_fields` is already generic over `model_class` and resolves 
aliases via `_get_known_fields`, so no other change is required. Models using 
`validation_alias` (`ColumnRef`, `FilterConfig`, `SortByConfig`) keep working, 
since `_get_known_fields` already collects `AliasChoices`.
   
   One consideration for reviewers: this makes previously-accepted payloads 
fail. That is the intent of the mixin, and it matches the existing top-level 
behaviour, but it is a behaviour change for any client currently passing extra 
nested keys.
   
   I'm happy to open a PR with the change plus a regression test in 
`tests/unit_tests/mcp_service/chart/test_chart_schemas.py`.
   
   ### Environment
   
   - Apache Superset 6.1.0 (docker), pydantic 2.11.7, fastmcp 3.4.5, Python 
3.10.20
   - Class definitions confirmed unchanged on `master` @ `7b351d5`
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to