Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[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)

Open
#10,015 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@MinitJain is already working on this.

Since Oct 15, 2026.

  • #10018 by @MinitJain — open

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
45/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
django, postgresql, python, redis
Domain
api, backend

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_response in apps/api/plane/utils/cache.py defaults to user=True. WorkspaceLabelsEndpoint.get (app/views/workspace/label.py) and WorkspaceEstimatesEndpoint.get (app/views/workspace/estimate.py) therefore save under per-user keys, e.g. /api/workspaces/<slug>/labels/:<user_id>.
  • LabelViewSet.partial_update and LabelViewSet.destroy (app/views/issue/label.py), and BulkEstimatePointEndpoint.partial_update and destroy (app/views/estimate/base.py), call invalidate_cache(..., url_params=True, user=False) without multiple=True. invalidate_cache_directly then deletes /api/workspaces/<slug>/labels/ exactly, a key that is never written.
  • LabelViewSet.create passes multiple=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):

  1. Create a label alpha in a project.
  2. GET /api/workspaces/<slug>/labels/ returns alpha, and the response is now cached for this user.
  3. PATCH /api/workspaces/<slug>/projects/<project_id>/issue-labels/<label_id>/ with {"name": "beta"} returns 200.
  4. GET /api/workspaces/<slug>/labels/ still returns alpha, while ?x=1 returns beta.
  5. DELETE the label, which returns 204. GET /api/workspaces/<slug>/labels/ still returns alpha, while ?x=1 returns [].

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_response from WorkspaceLabelsEndpoint and WorkspaceEstimatesEndpoint, as #7714 did for WorkspaceStatesEndpoint. 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

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from makeplane/plane

All issues in makeplane/plane

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.