codeant-ai-for-open-source[bot] commented on code in PR #38354:
URL: https://github.com/apache/superset/pull/38354#discussion_r2876674964


##########
superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx:
##########
@@ -81,33 +108,34 @@ export const useResultsPane = ({
         setForceQuery?.(false);
       }
       setIsLoading(false);
+      return;
     }
-    if (isRequest && !cache.has(queryFormData)) {
-      setIsLoading(true);
-      getChartDataRequest({
-        formData: queryFormData,
-        force: queryForce,
-        resultFormat: 'json',
-        resultType: 'results',
-        ownState,
+
+    // Fallback: fetch from API (legacy charts without queriesResponse)
+    setIsLoading(true);
+    getChartDataRequest({
+      formData: queryFormData,
+      force: queryForce,
+      resultFormat: 'json',
+      resultType: 'results',
+      ownState,
+    })
+      .then(({ json }) => {
+        setResultResp(ensureIsArray(json.result) as QueryResultInterface[]);
+        setResponseError('');
+        cache.set(queryFormData, json.result);
+        if (queryForce) {
+          setForceQuery?.(false);
+        }
       })
-        .then(({ json }) => {
-          setResultResp(ensureIsArray(json.result) as QueryResultInterface[]);
-          setResponseError('');
-          cache.set(queryFormData, json.result);
-          if (queryForce) {
-            setForceQuery?.(false);
-          }
-        })
-        .catch(response => {
-          getClientErrorObject(response).then(({ error, message }) => {
-            setResponseError(error || message || t('Sorry, an error 
occurred'));
-          });
-        })
-        .finally(() => {
-          setIsLoading(false);
+      .catch(response => {
+        getClientErrorObject(response).then(({ error, message }) => {
+          setResponseError(error || message || t('Sorry, an error occurred'));
         });
-    }
+      })
+      .finally(() => {
+        setIsLoading(false);
+      });
   }, [queryFormData, isRequest]);

Review Comment:
   **Suggestion:** The effect that populates the results table does not list 
the reused chart data (`queriesResponse`) in its dependency array, so when new 
chart data arrives with the same `queryFormData` and unchanged `isRequest`, the 
hook will not re-run and the table will show stale results; adding 
`queriesResponse` as a dependency ensures the hook reacts whenever the chart 
data changes. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Results pane may ignore updated queriesResponse from Redux.
   - ⚠️ Extra chart results API calls instead of reusing data.
   ```
   </details>
   
   ```suggestion
     }, [queryFormData, isRequest, queriesResponse]);
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Render any component that calls `useResultsPane` (hook defined in
   
`superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx:49-147`)
   with some `queryFormData` and `isRequest=true`, and with `queriesResponse` 
initially empty
   or undefined.
   
   2. On that initial render, the `useEffect` at `useResultsPane.tsx:74-139` 
runs because
   `queryFormData`/`isRequest` changed; the `queriesResponse?.length` check at 
lines 82-90
   fails, the cache miss path at lines 101-111 runs, and `getChartDataRequest` 
at lines
   115-123 fetches results and populates `resultResp`.
   
   3. Later, update the parent component so that it passes a new 
`queriesResponse` array
   (e.g., Redux chart data for the same `queryFormData`) while keeping 
`queryFormData` and
   `isRequest` unchanged; React re-renders the parent and `useResultsPane`, but 
the effect at
   74-139 does not re-run because its dependency array at line 139 is 
`[queryFormData,
   isRequest]` and does not include `queriesResponse`.
   
   4. Observe that the branch intended to reuse Redux data (`if 
(queriesResponse?.length &&
   'colnames' in queriesResponse[0])` at lines 82-98) is never executed for the 
new
   `queriesResponse` value and `resultResp` continues to reflect only the data 
from the
   earlier `getChartDataRequest` call, meaning the optimization to reuse chart 
data is
   effectively bypassed whenever `queriesResponse` changes independently of
   `queryFormData`/`isRequest`.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx
   **Line:** 139:139
   **Comment:**
        *Logic Error: The effect that populates the results table does not list 
the reused chart data (`queriesResponse`) in its dependency array, so when new 
chart data arrives with the same `queryFormData` and unchanged `isRequest`, the 
hook will not re-run and the table will show stale results; adding 
`queriesResponse` as a dependency ensures the hook reacts whenever the chart 
data changes.
   
   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.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38354&comment_hash=d5f255a429a4fedb82712c6bdf0cf1300157f585d03042ee1358ddec9bc4347d&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38354&comment_hash=d5f255a429a4fedb82712c6bdf0cf1300157f585d03042ee1358ddec9bc4347d&reaction=dislike'>👎</a>



##########
superset/charts/data/api.py:
##########
@@ -353,6 +354,70 @@ def data_from_cache(self, cache_key: str) -> Response:
 
         return self._get_data_response(command, True)
 
+    @expose("/data/stop", methods=("POST",))
+    @protect()
+    @statsd_metrics
+    def stop(self) -> Response:
+        """Stop a running chart query by client_id.
+        ---
+        post:
+          summary: Stop a running chart query
+          description: >-
+            Cancels a running chart query on the database engine using a
+            client-generated ID that was sent with the original data request.
+          requestBody:
+            required: true
+            content:
+              application/json:
+                schema:
+                  type: object
+                  properties:
+                    client_id:
+                      type: string
+          responses:
+            200:
+              description: Query cancelled
+            400:
+              $ref: '#/components/responses/400'
+            401:
+              $ref: '#/components/responses/401'
+            404:
+              $ref: '#/components/responses/404'
+        """
+        if not request.is_json or not request.json:
+            return self.response_400(message=_("Request is not JSON"))
+
+        client_id = request.json.get("client_id")
+        if not client_id:
+            return self.response_400(message=_("client_id is required"))
+
+        cancel_info = cache_manager.inflight_query_cache.get(client_id)
+        if not cancel_info:
+            return self.response_404()
+
+        database = db.session.query(Database).get(cancel_info["database_id"])

Review Comment:
   **Suggestion:** The stop endpoint cancels queries based solely on a 
client-provided `client_id` without verifying that the current user owns that 
inflight query, allowing any authenticated user who knows a `client_id` to 
cancel another user's query; you should compare the stored user identifier in 
`cancel_info` with the current user ID and return 403 when they don't match. 
[security]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ Authenticated users can cancel other users' running queries.
   - ⚠️ Enables targeted denial-of-service against specific users' charts.
   - ⚠️ Breaks expectation of per-user isolation for query control.
   ```
   </details>
   
   ```suggestion
           cancel_info = cache_manager.inflight_query_cache.get(client_id)
           if not cancel_info:
               return self.response_404()
   
           if cancel_info.get("user_id") != get_user_id():
               return self.response_403()
   
           database = db.session.query(Database).get(cancel_info["database_id"])
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. User A runs a chart using `ChartDataRestApi.data` in
   `superset/charts/data/api.py:120-190` with async queries enabled, which 
triggers async
   query handling that stores an inflight record in 
`cache_manager.inflight_query_cache`
   keyed by a client-generated `client_id` (used later by `stop()`).
   
   2. User B, a different authenticated Superset user, obtains User A's 
`client_id` for that
   inflight query (for example, by observing network traffic or logs in a 
shared environment
   where client IDs are visible).
   
   3. User B sends an authenticated POST request to the stop endpoint 
`/data/stop` handled by
   `ChartDataRestApi.stop` in `superset/charts/data/api.py:357-419` with JSON 
body
   `{"client_id": "<User A's client_id>"}`.
   
   4. In `stop()`, lines 394-398 fetch `cancel_info` from
   `cache_manager.inflight_query_cache` and immediately look up the `Database` 
using
   `cancel_info["database_id"]` without checking that `cancel_info` belongs to
   `get_user_id()`, so `database.db_engine_spec.cancel_query(...)` is executed 
against User
   A's query, allowing User B to cancel another user's running query.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/charts/data/api.py
   **Line:** 394:398
   **Comment:**
        *Security: The stop endpoint cancels queries based solely on a 
client-provided `client_id` without verifying that the current user owns that 
inflight query, allowing any authenticated user who knows a `client_id` to 
cancel another user's query; you should compare the stored user identifier in 
`cancel_info` with the current user ID and return 403 when they don't match.
   
   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.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38354&comment_hash=8100503e13b21f8201e6d07bbdd69bbfcf6457408f18d97edfe6fc3c5617441a&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38354&comment_hash=8100503e13b21f8201e6d07bbdd69bbfcf6457408f18d97edfe6fc3c5617441a&reaction=dislike'>👎</a>



##########
superset/models/core.py:
##########
@@ -692,34 +797,60 @@ def _execute_sql_with_mutation_and_logging(
 
         log_query = app.config["QUERY_LOGGER"]
 
-        def _log_query(sql_: str) -> None:
-            if log_query:
-                log_query(
-                    engine_url,
-                    sql_,
-                    schema,
-                    __name__,
-                    security_manager,
-                )
+        inflight_cache = None
+        if client_id and not self.db_engine_spec.has_implicit_cancel():
+            inflight_cache = cache_manager.inflight_query_cache
 
         with self.get_raw_connection(catalog=catalog, schema=schema) as conn:
             cursor = conn.cursor()
             rows = None
             description = None
 
+            # Capture cancel_query_id before execute (Postgres, MySQL, etc.)
+            cancel_info_stored = False
+            if inflight_cache is not None:
+                assert client_id is not None
+                cancel_info_stored = self._store_cancel_info(
+                    cursor, client_id, catalog, schema, inflight_cache,
+                )
+
             for i, statement in enumerate(script.statements):
                 sql_ = self.mutate_sql_based_on_config(
                     statement.format(),
                     is_split=True,
                 )
-                _log_query(sql_)
+                if log_query:
+                    log_query(
+                        engine_url, sql_, schema, __name__, security_manager,
+                    )
 
-                with event_logger.log_context(
-                    action="execute_sql",
-                    database=self,
-                    object_ref=__name__,
-                ):
-                    self.db_engine_spec.execute(cursor, sql_, self)
+                # For engines where cancel_query_id is only available DURING
+                # execute (e.g. Trino), run execute in a thread and poll for
+                # the query_id to appear on the cursor.
+                need_threaded = (
+                    inflight_cache is not None and not cancel_info_stored
+                )
+
+                if need_threaded:
+                    assert client_id is not None
+                    self._execute_with_cancel_capture(
+                        cursor, sql_, client_id, catalog, schema,
+                        inflight_cache,
+                    )
+                else:
+                    try:
+                        with event_logger.log_context(
+                            action="execute_sql",
+                            database=self,
+                            object_ref=__name__,
+                        ):
+                            self.db_engine_spec.execute(cursor, sql_, self)
+                    except Exception as ex:
+                        if cancel_info_stored:
+                            raise SupersetCancelQueryException(
+                                "Query was cancelled"
+                            ) from ex
+                        raise

Review Comment:
   **Suggestion:** In the synchronous execution path, any exception raised 
while `cancel_info_stored` is true is blindly converted into a 
`SupersetCancelQueryException`, which will incorrectly report normal database 
errors (syntax errors, connection issues, etc.) as "Query was cancelled" and 
hide the real failure cause; removing this special-case conversion restores 
correct error reporting. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Callers of Database.get_df see misleading cancellation errors.
   - ⚠️ Actual database issues hidden behind generic cancellation exception.
   - ⚠️ Troubleshooting query failures in Explore becomes significantly harder.
   ```
   </details>
   
   ```suggestion
                   else:
                       with event_logger.log_context(
                           action="execute_sql",
                           database=self,
                           object_ref=__name__,
                       ):
                           self.db_engine_spec.execute(cursor, sql_, self)
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Use a database backend where `get_cancel_query_id()` returns a non-None 
ID before
   execute (commented as "Postgres, MySQL, etc." at 
`superset/models/core.py:809-815`) and
   where `has_implicit_cancel()` returns False in the engine spec.
   
   2. From Python (e.g. a unit test), call `Database.get_df()` at
   `superset/models/core.py:897` with a non-None `client_id`, for example:
   
      `db.get_df("SELECT * FROM bad_syntax", client_id="test-client")`, so that
      `_execute_sql_with_mutation_and_logging()` at 
`superset/models/core.py:790` is invoked
      with that `client_id`.
   
   3. Inside `_execute_sql_with_mutation_and_logging()`, observe that 
`inflight_cache` is set
   (lines `800-802`) and `_store_cancel_info()` at 
`superset/models/core.py:750-772` is
   called, which obtains a `cancel_query_id` and sets `cancel_info_stored = 
True` for this
   cursor before the invalid SQL is executed.
   
   4. When the invalid SQL is executed in the non-threaded branch at
   `superset/models/core.py:840-847`, `self.db_engine_spec.execute(cursor, 
sql_, self)`
   raises a normal database exception (e.g. syntax error). The `except` block at
   `superset/models/core.py:848-853` sees `cancel_info_stored` is True and 
wraps this normal
   error in `SupersetCancelQueryException("Query was cancelled")`, causing 
callers of
   `get_df()` to receive a misleading "Query was cancelled" error instead of 
the real
   database failure.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/models/core.py
   **Line:** 840:853
   **Comment:**
        *Logic Error: In the synchronous execution path, any exception raised 
while `cancel_info_stored` is true is blindly converted into a 
`SupersetCancelQueryException`, which will incorrectly report normal database 
errors (syntax errors, connection issues, etc.) as "Query was cancelled" and 
hide the real failure cause; removing this special-case conversion restores 
correct error reporting.
   
   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.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38354&comment_hash=fadec928b54b59c741fed4d9ad5b7d32c0bd858c64d62622d1ed9d8d671c8b58&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38354&comment_hash=fadec928b54b59c741fed4d9ad5b7d32c0bd858c64d62622d1ed9d8d671c8b58&reaction=dislike'>👎</a>



##########
superset/charts/data/api.py:
##########
@@ -353,6 +354,70 @@ def data_from_cache(self, cache_key: str) -> Response:
 
         return self._get_data_response(command, True)
 
+    @expose("/data/stop", methods=("POST",))
+    @protect()
+    @statsd_metrics
+    def stop(self) -> Response:
+        """Stop a running chart query by client_id.
+        ---
+        post:
+          summary: Stop a running chart query
+          description: >-
+            Cancels a running chart query on the database engine using a
+            client-generated ID that was sent with the original data request.
+          requestBody:
+            required: true
+            content:
+              application/json:
+                schema:
+                  type: object
+                  properties:
+                    client_id:
+                      type: string
+          responses:
+            200:
+              description: Query cancelled
+            400:
+              $ref: '#/components/responses/400'
+            401:
+              $ref: '#/components/responses/401'
+            404:
+              $ref: '#/components/responses/404'
+        """
+        if not request.is_json or not request.json:
+            return self.response_400(message=_("Request is not JSON"))
+
+        client_id = request.json.get("client_id")
+        if not client_id:
+            return self.response_400(message=_("client_id is required"))
+
+        cancel_info = cache_manager.inflight_query_cache.get(client_id)
+        if not cancel_info:
+            return self.response_404()
+
+        database = db.session.query(Database).get(cancel_info["database_id"])
+        if not database:
+            return self.response_404()
+
+        if database.db_engine_spec.has_implicit_cancel():
+            cache_manager.inflight_query_cache.delete(client_id)
+            return self.response(200, message="Query cancelled (implicit)")
+
+        from contextlib import closing
+
+        with database.get_sqla_engine(
+            catalog=cancel_info.get("catalog"),
+            schema=cancel_info.get("schema"),
+        ) as engine:
+            with closing(engine.raw_connection()) as conn:
+                with closing(conn.cursor()) as cursor:
+                    database.db_engine_spec.cancel_query(
+                        cursor, None, cancel_info["cancel_query_id"]
+                    )

Review Comment:
   **Suggestion:** The `database.get_sqla_engine` return value is being used as 
a context manager, but it typically returns a SQLAlchemy engine which does not 
implement `__enter__/__exit__`, so `with database.get_sqla_engine(...) as 
engine:` will raise an AttributeError at runtime when this endpoint is hit; 
instead, get the engine normally and only wrap the raw connection and cursor in 
context managers. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ /data/stop crashes, queries cannot be cancelled.
   - ⚠️ Long-running chart queries keep consuming database resources.
   - ⚠️ Users see 500 error when pressing cancel query.
   ```
   </details>
   
   ```suggestion
           from contextlib import closing
   
           engine = database.get_sqla_engine(
               catalog=cancel_info.get("catalog"),
               schema=cancel_info.get("schema"),
           )
           with closing(engine.raw_connection()) as conn:
               with closing(conn.cursor()) as cursor:
                   database.db_engine_spec.cancel_query(
                       cursor, None, cancel_info["cancel_query_id"]
                   )
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Start Superset with this PR's code, ensuring charts are accessible 
(ChartDataRestApi in
   `superset/charts/data/api.py:72` is registered by FAB).
   
   2. Execute a chart query using the `/data` endpoint (`ChartDataRestApi.data` 
in
   `superset/charts/data/api.py:120-190`) with async queries enabled so that
   `cache_manager.inflight_query_cache` stores an entry containing 
`database_id` and
   `cancel_query_id`.
   
   3. While the query is still running, send an authenticated POST request to 
the stop
   endpoint `/data/stop` handled by `ChartDataRestApi.stop` in
   `superset/charts/data/api.py:357-419` with JSON body `{"client_id": "<the 
running query's
   client_id>"}`.
   
   4. When `stop()` executes line 408 `with database.get_sqla_engine(...) as 
engine:`,
   `Database.get_sqla_engine` (from `superset.models.core.Database`) returns a 
SQLAlchemy
   Engine object which does not implement `__enter__/__exit__`, causing Python 
to raise
   `AttributeError: __enter__` and the endpoint to return HTTP 500 instead of 
cancelling the
   query.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/charts/data/api.py
   **Line:** 408:416
   **Comment:**
        *Logic Error: The `database.get_sqla_engine` return value is being used 
as a context manager, but it typically returns a SQLAlchemy engine which does 
not implement `__enter__/__exit__`, so `with database.get_sqla_engine(...) as 
engine:` will raise an AttributeError at runtime when this endpoint is hit; 
instead, get the engine normally and only wrap the raw connection and cursor in 
context managers.
   
   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.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38354&comment_hash=8beb68f997c3268dc5971cdef30f96efd4de46ffc4105b7a48c9d34b716402e8&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38354&comment_hash=8beb68f997c3268dc5971cdef30f96efd4de46ffc4105b7a48c9d34b716402e8&reaction=dislike'>👎</a>



##########
docker/docker-bootstrap.sh:
##########
@@ -80,7 +80,7 @@ case "${1}" in
     ;;
   app)
     echo "Starting web app (using development server)..."
-    flask run -p $PORT --reload --debugger --without-threads --host=0.0.0.0 
--exclude-patterns "*/node_modules/*:*/.venv/*:*/build/*:*/__pycache__/*"
+    flask run -p $PORT --reload --debugger --with-threads --host=0.0.0.0 
--exclude-patterns "*/node_modules/*:*/.venv/*:*/build/*:*/__pycache__/*"

Review Comment:
   **Suggestion:** The added `--exclude-patterns` option to `flask run` is not 
a standard Flask CLI flag and will cause the command to fail with "no such 
option: --exclude-patterns", preventing the web app from starting in dev 
environments. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ Dev web server fails when starting with `app` mode.
   - ❌ Docker-based local Superset environment cannot be brought up.
   - ⚠️ Developers blocked from testing UI in containerized dev.
   ```
   </details>
   
   ```suggestion
       flask run -p $PORT --reload --debugger --with-threads --host=0.0.0.0
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. From the repository root, ensure the script `docker/docker-bootstrap.sh` 
is executable
   (`chmod +x docker/docker-bootstrap.sh` if needed).
   
   2. Start the dev web app path by running `bash docker/docker-bootstrap.sh 
app`, which
   passes `app` as `$1` into the case statement at 
`docker/docker-bootstrap.sh:70`.
   
   3. The `app)` branch at `docker/docker-bootstrap.sh:82-84` executes the line 
at
   `docker/docker-bootstrap.sh:83`: `flask run -p $PORT --reload --debugger 
--with-threads
   --host=0.0.0.0 --exclude-patterns 
"*/node_modules/*:*/.venv/*:*/build/*:*/__pycache__/*"`.
   
   4. The Flask CLI (standard `flask` entry point installed with Superset) does 
not define a
   `--exclude-patterns` option, so it exits with an error `Error: no such 
option:
   --exclude-patterns`, and the web app never starts.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** docker/docker-bootstrap.sh
   **Line:** 83:83
   **Comment:**
        *Logic Error: The added `--exclude-patterns` option to `flask run` is 
not a standard Flask CLI flag and will cause the command to fail with "no such 
option: --exclude-patterns", preventing the web app from starting in dev 
environments.
   
   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.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38354&comment_hash=72f1c66905da8f79a1fdba58db126712ab3e21a7087c7fbfab898de67874450c&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38354&comment_hash=72f1c66905da8f79a1fdba58db126712ab3e21a7087c7fbfab898de67874450c&reaction=dislike'>👎</a>



##########
superset/utils/cache_manager.py:
##########
@@ -235,6 +236,11 @@ def init_app(self, app: Flask) -> None:
             "EXPLORE_FORM_DATA_CACHE_CONFIG",
             required=True,
         )
+        self._init_cache(
+            app,
+            self._inflight_query_cache,
+            "INFLIGHT_QUERY_STATE_CACHE_CONFIG",
+        )

Review Comment:
   **Suggestion:** The new inflight query cache initialization unconditionally 
indexes `app.config["INFLIGHT_QUERY_STATE_CACHE_CONFIG"]` via `_init_cache`, so 
if this optional config key is not defined (which will be true on existing 
deployments that haven't added it yet), application startup will crash with a 
`KeyError` even though the cache is not marked as required. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ Superset Flask app fails to start with default config.
   - ❌ All HTTP endpoints unavailable due to startup crash.
   - ⚠️ New inflight query state feature unusable without manual config.
   ```
   </details>
   
   ```suggestion
           if "INFLIGHT_QUERY_STATE_CACHE_CONFIG" in app.config:
               self._init_cache(
                   app,
                   self._inflight_query_cache,
                   "INFLIGHT_QUERY_STATE_CACHE_CONFIG",
               )
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Use a Superset deployment that has not defined 
`INFLIGHT_QUERY_STATE_CACHE_CONFIG` in
   its configuration (the base config in `superset/config.py` in this repo 
snapshot does not
   contain this key).
   
   2. Start the Superset web application, which constructs the Flask app in
   `superset/app.py:create_app()` and calls `cache_manager.init_app(app)` (see
   `superset/app.py` where `from superset.extensions import cache_manager` is 
used and
   `cache_manager.init_app(app)` is invoked during startup).
   
   3. During `create_app()`, execution enters `CacheManager.init_app()` at
   `superset/utils/cache_manager.py:226-244`, reaching the new block:
   
      `self._init_cache(app, self._inflight_query_cache,
      "INFLIGHT_QUERY_STATE_CACHE_CONFIG")` (lines 239–243 in the diff).
   
   4. `_init_cache()` at `superset/utils/cache_manager.py:200-224` executes 
`cache_config =
   app.config[cache_config_key]` with 
`cache_config_key="INFLIGHT_QUERY_STATE_CACHE_CONFIG"`,
   raising a `KeyError` because the key is absent, which aborts application 
startup with a
   stack trace during initialization.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/utils/cache_manager.py
   **Line:** 239:243
   **Comment:**
        *Logic Error: The new inflight query cache initialization 
unconditionally indexes `app.config["INFLIGHT_QUERY_STATE_CACHE_CONFIG"]` via 
`_init_cache`, so if this optional config key is not defined (which will be 
true on existing deployments that haven't added it yet), application startup 
will crash with a `KeyError` even though the cache is not marked as required.
   
   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.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38354&comment_hash=25cc64eba2c9dc7490ea66890984f094b4a0f097c52c6e7fcdf5d6d86e56ec1b&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38354&comment_hash=25cc64eba2c9dc7490ea66890984f094b4a0f097c52c6e7fcdf5d6d86e56ec1b&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]

Reply via email to