Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

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

Aperta
#10,015 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

@MinitJain ci sta già lavorando.

Dal 15/10/2026.

  • #10018 di @MinitJain — aperta

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
45/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Attiva
Stack tecnologico
django, postgresql, python, redis
Ambito
api, backend

Direzione di ricerca

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.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

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)

Lingua principale
TypeScript
Stelle
61.1k
Fork
6.1k
Merge medio
1g 12h
PR unite (30g)
80

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di makeplane/plane

Tutte le issue di makeplane/plane

Issue simili

Altre issue su TypeScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.