codeant-ai-for-open-source[bot] commented on code in PR #37131:
URL: https://github.com/apache/superset/pull/37131#discussion_r3454664173
##########
superset-frontend/src/explore/exploreUtils/index.ts:
##########
@@ -398,11 +399,53 @@ export const exportChart = async ({
exportSource: 'chart',
});
} else {
- // SupersetClient.postForm calls getUrl({ endpoint }) internally, which
prepends
+ // Use AJAX blob download instead of form submission to enable error
handling.
+ // SupersetClient.postBlob calls getUrl({ endpoint }) internally, which
prepends
// appRoot — so the URL must NOT be pre-prefixed here.
- SupersetClient.postForm(url as string, {
- form_data: safeStringify(payload),
- });
+ try {
+ const response = await SupersetClient.postBlob(url as string, {
+ form_data: safeStringify(payload),
+ });
Review Comment:
**Suggestion:** `form_data` is being pre-serialized with `safeStringify`,
but `SupersetClient.postBlob()` sends `postPayload` through `callApi`, which
JSON-stringifies each form field again. This double-encodes the payload (e.g.
`"\"{...}\""`), so backend form parsing receives a string instead of an object
and can fail when accessing expected keys. Pass the raw `payload` object (or
disable form-field stringification for this request) to keep request format
compatible with existing chart export endpoints. [api mismatch]
<details>
<summary><b>Severity Level:</b> Critical 🚨</summary>
```mdx
- ❌ Explore JSON/CSV/XLSX exports raise 500 on parse.
- ❌ Backend /explore_json endpoint crashes on form_data access.
- ⚠️ Dashboard chart exports using legacy path likely fail.
```
</details>
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Trigger a chart data export (e.g. CSV/XLSX/JSON) from Explore so the
frontend calls
`exportChart(...)` in `superset-frontend/src/explore/exploreUtils/index.ts`
(function
starting around line 360). Because `onStartStreamingExport` is falsy,
execution enters the
`else` branch and sends a POST via `SupersetClient.postBlob(url as string, {
form_data:
safeStringify(payload) })` at lines 406–408.
2. `SupersetClient.postBlob` is implemented in
`superset-frontend/packages/superset-ui-core/src/connection/SupersetClientClass.ts`
lines
41–50, where it calls `this.post({ endpoint, postPayload: payload,
parseMethod: 'raw' })`.
That in turn calls `request(...)` in the same file, which invokes
`callApiAndParseWithTimeout` at lines 222–235.
3. `callApiAndParseWithTimeout` in
`superset-frontend/packages/superset-ui-core/src/connection/callApi/callApiAndParseWithTimeout.ts`
lines 25–38 delegates to `callApi(rest)`, implemented in
`superset-frontend/packages/superset-ui-core/src/connection/callApi/callApi.ts`
lines
63–78. Because the method is POST and `postPayload` is an object, the block
at lines
135–171 builds a `FormData` body. For the `form_data` key whose value is
already a JSON
string from `safeStringify(payload)`, the code executes
`JSON.stringify(value)` at line
155, producing a double-encoded string such as `"\"{...}\""` that is
appended to the form
data (lines 146–166).
4. On the backend, chart requests are parsed by `get_form_data()` in
`superset/views/utils.py` lines 202–236. It reads
`request.form.get("form_data")` into
`request_form_data` at line 221 and passes it to `loads_request_json()` at
lines 195–199,
which calls `json.loads` once. For the double-encoded `"\"{...}\""` value,
`json.loads`
returns a plain string instead of a dict. `get_form_data` then executes
`parsed_form_data.get("queries")` at line 228, but since `parsed_form_data`
is a string,
this raises `AttributeError: 'str' object has no attribute 'get'`, causing
chart export
endpoints like `explore_json` in `superset/views/core.py` lines 297–80 (and
`/api/v1/chart/data` when using form-data) to fail with a 500 instead of
returning the
requested export file.
```
</details>
[](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=d3a235b73c9e49b1970855e4a631fec6&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
[](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=d3a235b73c9e49b1970855e4a631fec6&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
*(Use Cmd/Ctrl + Click for best experience)*
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset-frontend/src/explore/exploreUtils/index.ts
**Line:** 406:408
**Comment:**
*Api Mismatch: `form_data` is being pre-serialized with
`safeStringify`, but `SupersetClient.postBlob()` sends `postPayload` through
`callApi`, which JSON-stringifies each form field again. This double-encodes
the payload (e.g. `"\"{...}\""`), so backend form parsing receives a string
instead of an object and can fail when accessing expected keys. Pass the raw
`payload` object (or disable form-field stringification for this request) to
keep request format compatible with existing chart export endpoints.
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask
user if the user wants to fix the rest of the comments as well. if said yes,
then fetch all the comments validate the correctness and implement a minimal fix
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F37131&comment_hash=ed582e7849351922ca722785fb46e9239c5fe9ac2c4ff2c159c32ed7dca08fd4&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F37131&comment_hash=ed582e7849351922ca722785fb46e9239c5fe9ac2c4ff2c159c32ed7dca08fd4&reaction=dislike'>👎</a>
--
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]