Bug Report: Stale progress file causes wrong status after disable/uninstall
Severity: Medium
Category: Error Handling
Platform: All (macOS, Linux, Windows/WSL2)
Confidence: Confirmed (API-tested on macOS Apple Silicon)
Description
After installing an extension, the progress file persists through disable and uninstall operations. Because _compute_extension_status() checks progress files before checking actual extension state, a stale progress file overrides the real status. An uninstalled extension can show as "installing" in the UI.
Affected File(s)
dream-server/extensions/services/dashboard-api/routers/extensions.py (lines 103-128, 898-980, 983-1027)
Root Cause
The disable_extension() and uninstall_extension() endpoints do not clean up the progress file in data/extension-progress/{service_id}.json. The stale progress file (with status: "started") persists, and _compute_extension_status() checks it first (lines 103-128). Since _is_stale() uses a 300-second window for "started" status, the stale file takes priority over the actual extension state for up to 5 minutes.
The only cleanup mechanism is _cleanup_stale_progress() which runs lazily on catalog refresh and only removes files after 15 minutes (started) or 1 hour (other states).
Evidence
# _compute_extension_status checks progress FIRST (line 103-128)
progress = _read_progress(ext_id)
if progress:
ps = progress.get("status", "")
if ps == "started":
if not _is_stale(progress.get("updated_at", ""), max_age_seconds=300):
svc = services_by_id.get(ext_id)
if not (svc and svc.status == "healthy"):
return "installing" # <-- returned even after uninstall!
Platform Analysis
- macOS: Affected — confirmed via API testing
- Linux: Affected — same Python code path
- Windows/WSL2: Affected — same Python code path
Reproduction
- Install an extension:
POST /api/extensions/chromadb/install
- Wait for status to show "enabled" or "installing"
- Disable:
POST /api/extensions/chromadb/disable
- Check status:
GET /api/extensions/chromadb → shows "installing" instead of "disabled"
- Uninstall:
DELETE /api/extensions/chromadb
- Check status:
GET /api/extensions/chromadb → shows "installing" instead of "not_installed"
Impact
- Extension status is wrong in the UI for up to 5 minutes after disable/uninstall
- Users see a spinner ("installing") for an extension they just removed
- Confusing UX — user might think the operation failed
Suggested Approach
Delete the progress file in both disable_extension() and uninstall_extension() (and purge_extension_data()) after the operation completes.
Bug Report: Stale progress file causes wrong status after disable/uninstall
Severity: Medium
Category: Error Handling
Platform: All (macOS, Linux, Windows/WSL2)
Confidence: Confirmed (API-tested on macOS Apple Silicon)
Description
After installing an extension, the progress file persists through disable and uninstall operations. Because
_compute_extension_status()checks progress files before checking actual extension state, a stale progress file overrides the real status. An uninstalled extension can show as "installing" in the UI.Affected File(s)
dream-server/extensions/services/dashboard-api/routers/extensions.py(lines 103-128, 898-980, 983-1027)Root Cause
The
disable_extension()anduninstall_extension()endpoints do not clean up the progress file indata/extension-progress/{service_id}.json. The stale progress file (withstatus: "started") persists, and_compute_extension_status()checks it first (lines 103-128). Since_is_stale()uses a 300-second window for "started" status, the stale file takes priority over the actual extension state for up to 5 minutes.The only cleanup mechanism is
_cleanup_stale_progress()which runs lazily on catalog refresh and only removes files after 15 minutes (started) or 1 hour (other states).Evidence
Platform Analysis
Reproduction
POST /api/extensions/chromadb/installPOST /api/extensions/chromadb/disableGET /api/extensions/chromadb→ shows "installing" instead of "disabled"DELETE /api/extensions/chromadbGET /api/extensions/chromadb→ shows "installing" instead of "not_installed"Impact
Suggested Approach
Delete the progress file in both
disable_extension()anduninstall_extension()(andpurge_extension_data()) after the operation completes.