Skip to content

[Bug] Renaming a voice makes the list look stale or empty in other tabs (WS event dropped from sync endpoints) #1561

Description

@paoloantinori

Problem

After renaming a cloned voice from the profile page, the voices panel does not refresh — the old name keeps showing until a full reload, and a reload landing in the wrong moment can present an empty voices panel, which looks like all voices were deleted (they are not: the rows and reference audio are intact; a fresh load shows everything again).

Root cause (verified on main @ e4c1ef0)

  • PUT /profiles/{id} (update_profile), DELETE /profiles/{id}, DELETE /profiles/{id}/consent, the history star/clear/delete routes and the export recorders are sync FastAPI endpoints → Starlette runs their bodies in threadpool workers, where asyncio.get_running_loop() raises RuntimeError.
  • event_bus.emit() (backend/core/event_bus.py) treated that exception as "no event loop — event dropped" (DEBUG log only), so the profiles WebSocket event was silently dropped for exactly the mutations users notice most.
  • The frontend only refetches the voice list on that WS event (useRealtimeEventsloadProfiles), so every open tab kept stale state.
  • Compounding it: the initial list load ran exactly once with no retry (useAppData), so a transient failure on first fetch left an empty panel until some later WS event or reload — the "my voices are gone" presentation.

Evidence: live probe against a running backend — WS client connected, PUT rename returned 200 and the row updated in SQLite, but no {"kind":"profiles"} frame ever arrived on the socket (3s window). Async endpoints (lock/unlock/consent-record) emit fine; only sync ones drop.

Repro

  1. Open the app in two tabs (or rename and watch the same tab's sidebar).
  2. Rename a cloned voice (profile page → Edit → rename → Save).
  3. The list still shows the old name; the other tab never updates.

Fix

emit() captures the serving loop in subscribe() and hands off from foreign threads via call_soon_threadsafe; async callers unchanged. Plus the initial loads retry until first success (WS-triggered reloads keep the keep-previous-list behavior). Regression test included (fails on old emit, passes on fix); PR to follow.

— happy to link the PR: paoloantinori

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions