HKUDS/DeepTutor · error · HTTPException
t("api.partner_not_found_or_not_running")
Error message
t("api.partner_not_found_or_not_running") What it means
404 raised by the DELETE-stop route POST /api/partners/{partner_id}/stop when PartnerManager.stop_partner() returns a falsy value, meaning no partner with that id exists or it was not in a running state to stop. It is an explicit FastAPI HTTPException, so it always surfaces as an HTTP 404 with the i18n message 'api.partner_not_found_or_not_running'.
Source
Thrown at deeptutor/api/routers/partners.py:803
mgr.save_config(partner_id, cfg)
return _stopped_partner_dict(partner_id, cfg)
@router.post("/{partner_id}/start", dependencies=_MANAGEABLE)
async def start_partner(partner_id: str):
instance = await _ensure_running_partner(partner_id, allow_stopped=True)
# An explicit start is a persisted "run on boot" intent — so the partner
# comes back in this state after a DeepTutor restart (a manual /stop clears
# it; a lazy chat-driven start does NOT reach here, so it can't flip it).
get_partner_manager().save_config(partner_id, instance.config, auto_start=True)
return instance.to_dict(mask_secrets=True)
@router.post("/{partner_id}/stop", dependencies=_MANAGEABLE)
async def stop_partner(partner_id: str):
stopped = await get_partner_manager().stop_partner(partner_id)
if not stopped:
raise HTTPException(status_code=404, detail=t("api.partner_not_found_or_not_running"))
return {"partner_id": partner_id, "stopped": True}
@router.delete("/{partner_id}", dependencies=_MANAGEABLE)
async def destroy_partner(partner_id: str):
destroyed = await get_partner_manager().destroy_partner(partner_id)
if not destroyed:
raise HTTPException(status_code=404, detail=t("api.partner_not_found"))
return {"partner_id": partner_id, "destroyed": True}
@router.post("/{partner_id}/channels/reload", dependencies=_MANAGEABLE)
async def reload_partner_channels(partner_id: str):
mgr = get_partner_manager()
instance = mgr.get_partner(partner_id)
if not instance or not instance.running:
raise HTTPException(status_code=404, detail=t("api.partner_not_running"))
try:View on GitHub (pinned to 3e82f13042)
Solutions
- Verify the partner exists and its running state via GET /partners before stopping (or use the list from GET /partners)
- Re-sync the partner list (GET /partners) and confirm the id, then retry the stop
- If the id is stale because the partner was destroyed, drop it from your UI state instead of retrying
Example fix
// before
await client.post(f"/partners/{partner_id}/stop")
// after
partners = (await client.get("/partners")).json()
if any(p["partner_id"] == partner_id for p in partners):
await client.post(f"/partners/{partner_id}/stop") Defensive patterns
Strategy: validation
Validate before calling
partners = (await client.get("/api/v1/partners")).json()
ids = {p["partner_id"] for p in partners}
assert partner_id in ids, "partner does not exist" Try / catch
except HTTPStatusError as e:
if e.response.status_code == 404:
# already stopped or unknown id — refresh state Prevention
- Cache the partner list and refresh before lifecycle calls
- Disable the Stop button once a stop request is in flight
When it happens
Trigger: Calling POST /partners/{id}/stop with an id that was never created, was already destroyed, or is already stopped (stop_partner returns False when nothing transitioned).
Common situations: UI holds a stale partner list after another tab destroyed the partner; double-clicking Stop fires the second request after the first already stopped it; typo'd partner_id from env/config.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- t("api.partner_not_running")
- Record not found
- Record or target notebook not found
- str(exc)
- Operation not found
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/e844a4edd6fc8f63.
Report an issue: GitHub.