hunter3x3-tech opened a new issue, #44385:
URL: https://github.com/apache/superset/issues/44385
### Bug description
# DELETE leaves stale contextual cache mappings, causing deleted
filter/form-data keys to be reused
## Bug description
The temporary-state DELETE paths for dashboard filter state and Explore form
data remove the primary cache entry, but can leave the secondary contextual
mapping pointing to the deleted key.
As a result, a subsequent POST from the same session/tab/context can reuse a
key that was previously deleted.
This affects both:
* `DashboardFilterStateRestApi`
* `ExploreFormDataRestApi`
The behavior is present on current `master` and the same underlying logic is
present in 6.1.0.
## Root cause
Temporary state creation keeps a secondary mapping so the same
session/tab/resource can reuse an existing generated key.
For dashboard filter state, the mapping is based on:
```python
contextual_key = cache_key(
session.get("_id"),
tab_id,
resource_id,
)
```
The DELETE command attempts to remove the same mapping:
```python
tab_id = cmd_params.tab_id
contextual_key = cache_key(
session.get("_id"),
tab_id,
resource_id,
)
cache_manager.filter_state_cache.delete(contextual_key)
```
However, the DELETE API creates the command parameters without a `tab_id`.
Effectively, the command receives:
```python
cmd_params.tab_id is None
```
so it attempts to delete a mapping for:
```text
<session>;None;<resource>
```
rather than the mapping originally created for, for example:
```text
<session>;1;<resource>
```
The primary state entry is deleted successfully, so the DELETE request
returns success, while the actual contextual mapping remains.
`ExploreFormDataRestApi` has the same mismatch: `DeleteFormDataCommand` uses
`cmd_params.tab_id` to construct the contextual key, but the DELETE endpoint
passes only `key`.
## Why this matters
On the next POST from the same context, the create path reads the stale
contextual mapping:
```python
key = cache_manager.filter_state_cache.get(contextual_key)
if not key or not tab_id:
key = random_key()
```
Because the stale mapping still returns the previously deleted key and
`tab_id` is present, no new random key is generated.
The deleted key is then used again for the newly created state.
The same reuse pattern exists in `CreateFormDataCommand`.
## Reproduction
Using a dashboard with filter-state access:
1. Create filter state with a tab id:
```http
POST /api/v1/dashboard/<dashboard_id>/filter_state?tab_id=1
```
with a valid JSON-string value representing `State A`.
Record the returned key as `K1`.
2. Delete it:
```http
DELETE /api/v1/dashboard/<dashboard_id>/filter_state/K1
```
The request returns success.
3. Verify the primary entry is gone:
```http
GET /api/v1/dashboard/<dashboard_id>/filter_state/K1
```
This should return 404.
4. Create another filter state using the same browser session, dashboard and
`tab_id=1`, this time with `State B`:
```http
POST /api/v1/dashboard/<dashboard_id>/filter_state?tab_id=1
```
### Actual behavior
The second POST can return:
```text
K1
```
again.
The stale contextual mapping still points to the previously deleted key, so
the create path reuses it and recreates the primary state entry under `K1`.
A subsequent GET of `K1` can therefore return `State B`.
### Expected behavior
A successful DELETE should invalidate both the primary entry and its
contextual mapping.
After deletion, creating state again in the same context should generate a
fresh key:
```text
K2 != K1
```
## Affected code
Dashboard filter state:
```text
superset/commands/dashboard/filter_state/create.py
superset/commands/dashboard/filter_state/delete.py
superset/temporary_cache/api.py
```
Explore form data:
```text
superset/commands/explore/form_data/create.py
superset/commands/explore/form_data/delete.py
superset/explore/form_data/api.py
```
## Existing test gap
Current tests verify that DELETE returns successfully, but do not verify
that the contextual mapping is removed.
A regression test could exercise:
```text
create with tab_id=1
→ delete returned key
→ create again with the same context
→ assert second key != deleted key
```
The existing Explore command test is especially close to this scenario: it
creates form data with `tab_id=1`, invokes `DeleteFormDataCommand` without a
`tab_id`, and only asserts that deletion returns `True`.
## Historical intent
PR #18576 introduced the contextual secondary mapping used for key reuse.
Its design explicitly states that the secondary mapping should be kept in
sync with DELETE events.
The current API/command contract appears to prevent that synchronization
because the DELETE routes do not supply the context required by their delete
commands.
## Suggested remediation direction
The DELETE path needs a reliable way to identify and remove the contextual
mapping associated with the primary key.
Simply deleting the primary cache entry is insufficient because the
surviving mapping can cause that key to be reused later.
Possible approaches include passing and preserving the necessary context on
DELETE, or maintaining a reverse association that allows the contextual mapping
to be invalidated from the primary key.
## Environment
* Superset: current `master`
* Also present in the corresponding temporary-cache logic in Superset 6.1.0
* Python: Not applicable for source-level analysis
* Node: Not applicable
* Browser: Not applicable
### Screenshots/recordings
_No response_
### Superset version
6.1.0
### Python version
I don't know
### Node version
I don't know
### Browser
Chrome
### Additional context
_No response_
### Checklist
- [x] I have searched Superset docs and Slack and didn't find a solution to
my problem.
- [x] I have searched the GitHub issue tracker and didn't find a similar bug
report.
- [x] I have checked Superset's logs for errors and if I found a relevant
Python stacktrace, I included it here as text in the "additional context"
section.
--
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]