{"record":{"id":"421bc5dd8e0adfe8","repo":"odysseus-dev/odysseus","slug":"selected-model-endpoint-was-removed-pick-another","errorCode":null,"errorMessage":"Selected model endpoint was removed. Pick another model in Settings.","messagePattern":"Selected model endpoint was removed\\. Pick another model in Settings\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"routes/chat_routes.py","lineNumber":700,"sourceCode":"        message = chat_request.message\n        session = chat_request.session\n        att_ids = chat_request.attachments or []\n        use_web = chat_request.use_web\n        use_research = chat_request.use_research\n        time_filter = chat_request.time_filter\n        preset_id = chat_request.preset_id\n\n        # Verify the caller owns this session before loading it.\n        # Without this, any authenticated user can post into another user's chat.\n        _verify_session_owner(request, session)\n\n        try:\n            sess = session_manager.get_session(session)\n        except KeyError:\n            raise HTTPException(404, f\"Session '{session}' not found\")\n        owner = effective_user(request)\n        if _clear_orphaned_session_endpoint(sess, owner=owner):\n            raise HTTPException(400, \"Selected model endpoint was removed. Pick another model in Settings.\")\n\n        # Empty model + live endpoint = setup race (Issue #587). Repair from\n        # the endpoint's cached model list before privilege checks, which\n        # otherwise see \"\" and behave inconsistently with the allowlist.\n        _recover_empty_session_model(sess, session, owner=owner)\n        if not getattr(sess, \"model\", \"\").strip():\n            raise HTTPException(\n                400,\n                \"No model selected for this chat. Open the model picker and choose one before sending.\",\n            )\n        if not (getattr(sess, \"endpoint_url\", \"\") or \"\").strip():\n            raise HTTPException(400, \"Selected model endpoint is not configured\")\n\n        # Same allowed_models + daily-cap gate as chat_stream (mirror so the\n        # non-streaming path can't be used to bypass).\n        _enforce_chat_privileges(request, sess)\n\n        tool_policy = build_effective_tool_policy(last_user_message=message)","sourceCodeStart":682,"sourceCodeEnd":718,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/chat_routes.py#L682-L718","documentation":"The session references an endpoint (model provider route) that no longer exists; _clear_orphaned_session_endpoint detected the endpoint was deleted, cleared it from the session, and the handler rejects with 400 telling the user to re-pick a model. This prevents calls to a dead upstream URL.","triggerScenarios":"Endpoint deleted or re-created in Settings after the session was bound to it; session restored from backup referencing an endpoint ID that was removed; multi-admin environments where one admin prunes endpoints.","commonSituations":"User had a chat open on a custom OpenAI-compatible endpoint that was later deleted; migration or cleanup scripts removed endpoint records while sessions still pointed at them.","solutions":["Open Settings in the client, pick a live endpoint/model for this chat, then resend","If the endpoint should exist, re-create it in endpoint management and re-select it","Administrators: warn users before deleting endpoints that sessions depend on"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const endpoints = await fetch('/api/endpoints').then(r=>r.json());\nif (!endpoints.some(ep => ep.id === session.endpoint_id)) { promptEndpointRebind(); }","typeGuard":null,"tryCatchPattern":"try { await send(...); } catch (e) { if (e.status === 400 && /endpoint was removed/.test(e.message)) openSettingsForModelPick(); else throw e; }","preventionTips":["Validate the session's endpoint still exists before first send after reconnect","Admins: audit dependent sessions before deleting an endpoint"],"tags":["endpoint","configuration","chat","client-error"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}