ruvnet/RuView · warning · HTTPException
Client {client_id} not found
Error message
Client {client_id} not found What it means
Deliberate 404 raised by DELETE /stream/clients/{client_id} in archive/v1/src/api/routers/stream.py when connection_manager.disconnect(client_id) returns False — meaning no active connection matches the given id. Unlike the surrounding 500 catch-alls, this is a controlled, expected outcome of a racing or stale request, not an internal failure.
Source
Thrown at archive/v1/src/api/routers/stream.py:448
raise HTTPException(
status_code=500,
detail="An internal error occurred. Please try again later."
)
@router.delete("/clients/{client_id}")
async def disconnect_client(
client_id: str,
current_user: Dict = Depends(require_auth)
):
"""Disconnect a specific WebSocket client."""
try:
logger.info(f"Disconnecting client {client_id} by user: {current_user['id']}")
success = await connection_manager.disconnect(client_id)
if not success:
raise HTTPException(
status_code=404,
detail=f"Client {client_id} not found"
)
return {
"message": f"Client {client_id} disconnected successfully",
"timestamp": datetime.utcnow().isoformat()
}
except HTTPException:
raise
except Exception as e:
logger.error(f"Error disconnecting client: {e}")
raise HTTPException(
status_code=500,
detail="An internal error occurred. Please try again later."
)
View on GitHub (pinned to 4685618388)
Solutions
- Re-fetch GET /stream/clients and confirm the id is still present before retrying
- Treat 404 as success when the goal is only 'make sure this client is gone'
- Copy ids verbatim from the current clients listing; never construct them by hand or from stale logs
- If the id should exist, compare it byte-for-byte with the listing (encoding, whitespace, case) to rule out a formatting mismatch
Example fix
# before (caller treats 404 as an error)
resp = requests.delete(f"{API}/stream/clients/{client_id}")
resp.raise_for_status()
# after (caller treats 404 as already-gone)
resp = requests.delete(f"{API}/stream/clients/{client_id}")
if resp.status_code == 404:
logger.info(f"client {client_id} already disconnected")
else:
resp.raise_for_status() Defensive patterns
Strategy: type-guard
Validate before calling
import httpx
listing = httpx.get(f"{API}/stream/clients", headers=auth, timeout=10).json()
known_ids = {c["id"] for c in listing["clients"]}
if client_id not in known_ids:
print(f"{client_id} not connected; nothing to disconnect") Type guard
def client_connected(client_id: str, listing: dict) -> bool:
return any(c.get("id") == client_id for c in listing.get("clients", [])) Try / catch
import httpx
try:
resp = httpx.delete(f"{API}/stream/clients/{client_id}", headers=auth, timeout=10)
resp.raise_for_status()
except httpx.HTTPStatusError as e:
if e.response.status_code == 404:
pass # already gone — treat as success
else:
raise Prevention
- Always re-fetch GET /stream/clients immediately before disconnecting a listed id
- Copy ids verbatim from the listing; never assemble them from logs or hand-typed fragments
- Treat 404 as the idempotent-success case in admin UIs and scripts
When it happens
Trigger: DELETE /stream/clients/{client_id} with an id that already disconnected; using a stale id captured from an earlier GET /stream/clients listing; a double-click in an admin UI sending the delete twice, where the second call finds nothing; id formatting mismatch (whitespace, URL-encoding, wrong case) between the listing and the path parameter.
Common situations: Race between listing clients and disconnecting one (client drops itself in between); UI not refreshing the client list after a disconnect; copy-pasting ids from logs of a previous session instead of the current GET /stream/clients response.
Related errors
- An internal error occurred. Please try again later.
- Endpoint not available in production
- Zone '{zone_id}' not found
- JWT authentication is not configured. In development mode, e
- Authentication required
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/b4a736c644fe3daf.
Report an issue: GitHub.