[bug]: Workspace labels/estimates API returns stale data for up to 2 hours after label rename/delete or estimate changes (per-user cache not invalidated)
Maintainers usually reply within 1 day
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 45/100
Research direction
Start with invalidate_cache and cache_response in apps/api/plane/utils/cache.py, then the write paths in app/views/issue/label.py, app/views/estimate/base.py and app/views/project/base.py. Ask maintainers first whether they want Option A (clear every user's key) or Option B (drop @cache_response), since the issue leaves that open. Done means that after a label or estimate write, a different user's GET on the workspace labels or estimates endpoint returns the new data.
Written by the indexing model from the issue text.
Description
Is there an existing issue for this?
- I have searched the existing issues
Current behavior
GET /api/workspaces/<slug>/labels/ and GET /api/workspaces/<slug>/estimates/ are cached separately for each user for 2 hours when DEBUG is off (the default in plane.settings.production). Several writes don't clear that cache, so these endpoints keep returning the old response until it expires.
Expected: after a label or estimate changes, the next request to these endpoints returns current data.
Actual: the response cached before the change is returned for up to 2 hours.
Confirmed affected operations:
| Operation | Endpoint | Result |
|---|---|---|
| Rename a label | PATCH /api/workspaces/<slug>/projects/<project_id>/issue-labels/<id>/ |
workspace labels still show the old name |
| Delete a label | DELETE …/issue-labels/<id>/ |
deleted label still returned |
| Update an estimate | PATCH /api/workspaces/<slug>/projects/<project_id>/estimates/<id>/ |
old point values still returned |
| Delete an estimate | DELETE …/estimates/<id>/ |
deleted estimate still returned |
| Enable an estimate on a project | PATCH /api/workspaces/<slug>/projects/<project_id>/ with {"estimate": "<id>"} |
workspace estimates still return the pre-change response (empty in the test) |
Two operations worked correctly in the same test:
- Creating a label clears the cache. This was fixed in #6587.
- Creating an estimate on its own changes nothing visible. The workspace endpoint only returns estimates attached to a project, so the response is the same either way.
Why it happens
cache_responseinapps/api/plane/utils/cache.pydefaults touser=True.WorkspaceLabelsEndpoint.get(app/views/workspace/label.py) andWorkspaceEstimatesEndpoint.get(app/views/workspace/estimate.py) therefore save under per-user keys, e.g./api/workspaces/<slug>/labels/:<user_id>.LabelViewSet.partial_updateandLabelViewSet.destroy(app/views/issue/label.py), andBulkEstimatePointEndpoint.partial_updateanddestroy(app/views/estimate/base.py), callinvalidate_cache(..., url_params=True, user=False)withoutmultiple=True.invalidate_cache_directlythen deletes/api/workspaces/<slug>/labels/exactly, a key that is never written.LabelViewSet.createpassesmultiple=True, which deletes by pattern (*<key>*) and clears every user's entry. #6587 fixed label create this way.ProjectViewSet.partial_update(app/views/project/base.py) has no cache clearing at all, so enabling an estimate on a project isn't reflected.
Steps to reproduce
I reproduced this against an isolated API built from preview @ 4605f0078f. It used plane.settings.production, DEBUG=False, Redis (Valkey) and Postgres, with real HTTP requests authenticated by session cookie. I did not test the web UI.
The cache is per user, so each check below must be made by a user whose cached response was stored before the write. To compare against the database, request the same URL with a dummy query string (e.g. ?x=1). That's a different cache key, so it returns current data.
Labels (one project admin):
- Create a label
alphain a project. GET /api/workspaces/<slug>/labels/returnsalpha, and the response is now cached for this user.PATCH /api/workspaces/<slug>/projects/<project_id>/issue-labels/<label_id>/with{"name": "beta"}returns 200.GET /api/workspaces/<slug>/labels/still returnsalpha, while?x=1returnsbeta.DELETEthe label, which returns 204.GET /api/workspaces/<slug>/labels/still returnsalpha, while?x=1returns[].
Enabling an estimate (user A, project admin; workspace has no estimates in use):
6. GET /api/workspaces/<slug>/estimates/ returns [], which is now cached for user A.
7. POST /api/workspaces/<slug>/projects/<project_id>/estimates/ creates an estimate with points 1, 2. GET …/estimates/ still returns [], and so does ?x=1, so nothing is stale yet.
8. PATCH /api/workspaces/<slug>/projects/<project_id>/ with {"estimate": "<estimate_id>"} returns 200.
9. GET /api/workspaces/<slug>/estimates/ still returns [] for user A, while ?x=1 returns the estimate with points 1, 2.
Updating and deleting an estimate (user B, project admin; writes done by user A):
10. After step 8, user B requests GET /api/workspaces/<slug>/estimates/ for the first time. It returns the estimate with points 1, 2, now cached for user B.
11. User A sends PATCH /api/workspaces/<slug>/projects/<project_id>/estimates/<estimate_id>/ with the point values changed to v10, v20, which returns 200. User B's GET …/estimates/ still returns 1, 2, while ?x=1 returns v10, v20.
12. User A sends DELETE …/estimates/<estimate_id>/, which returns 204. User B's GET …/estimates/ still returns the estimate with points 1, 2, while ?x=1 returns [].
Checked at the end of the run, the cached label key had a Redis TTL of about 7,185 s, consistent with the 2-hour timeout.
Not tested: other writes that may also leave these responses stale. I haven't verified them:
- v1 API label writes
- the estimate-point endpoints (
…/estimates/<id>/estimate-points/) - project membership changes, since the label/estimate list depends on which projects the user belongs to
Question for maintainers
Which approach would you prefer?
- Option A: Fix cache clearing. Change the affected calls so they clear every user's cached copy, as #6587 did for label create, and add clearing to project estimate selection. Other write paths that change these responses (listed above) would need auditing, and possibly the same treatment.
- Option B: Remove caching from these two endpoints. Drop
@cache_responsefromWorkspaceLabelsEndpointandWorkspaceEstimatesEndpoint, as #7714 did forWorkspaceStatesEndpoint. That avoids staleness from any write path, including ones that don't clear the cache explicitly. The trade-off is that every request would hit the database, which may matter for performance on larger workspaces.
I'm happy to implement whichever approach you prefer and add regression tests.
Environment
Production
Browser
Other (reproduced at API level; UI not tested)
Edition
Community
Version
preview @ 4605f0078f (apps/api 1.4.2)
- Dominant language
- TypeScript
- Stars
- 60.7k
- Forks
- 6k
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 79
Getting set up
- Ships a Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from makeplane/plane
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
Maintainers usually reply within 1 day
-
[bug]: Email notifications show a broken avatar for users without a profile photoPossibly taken @gurnoorpannu claimed this 4 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
makeplane/plane#10009 · 1 comment ·
Maintainers usually reply within 1 day
-
🐛 Bug: Calendar work items cannot be opened on mobilePossibly taken @pennnnnnnnnn claimed this 6 days ago. Open
Difficulty 1/5 Under an hour Newbie friendliness 75/100
Maintainers usually reply within 1 day
-
[bug]: First day of the week section not translated when Idioma is EspañolPossibly taken @deepcfr claimed this 9 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
makeplane/plane#9967 · 2 comments ·
Maintainers usually reply within 1 day
-
[bug]: First day of the week section not translated when Idioma is EspañolPossibly taken @Indira-kumar claimed this 6 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 1/5 Under an hour Newbie friendliness 65/100
521xueweihan/HelloGitHub#4025 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
voidzero-dev/void#478 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 69/100
Small-tailqwq/dsh-deep-whale#207 ·
Maintainers usually reply within 1 day
-
The inspector never shows the instances field, so scaling out is unreachablePossibly taken @Mrkewl claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
xevrion/breakscale#96 ·
Maintainers usually reply within 4 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Flux159/mcp-server-kubernetes#384 ·