{"record":{"id":"dd2dd46560557b74","repo":"odysseus-dev/odysseus","slug":"no-model-selected-for-this-chat-open-the-model-pi","errorCode":null,"errorMessage":"No model selected for this chat. Open the model picker and choose one before sending.","messagePattern":"No model selected for this chat\\. Open the model picker and choose one before sending\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"routes/chat_routes.py","lineNumber":707,"sourceCode":"\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)\n        allow_tool_preprocessing = not tool_policy.block_all_tool_calls\n\n        # Inline memory command\n        memory_response = None\n        if not tool_policy.blocks(\"manage_memory\"):\n            memory_response = await chat_handler.handle_memory_command(sess, message)\n        if memory_response:","sourceCodeStart":689,"sourceCodeEnd":725,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/chat_routes.py#L689-L725","documentation":"After orphaned-endpoint cleanup and the Issue #587 recovery attempt (which tries to repopulate the model from the endpoint's cached model list), the session still has an empty model string. The handler rejects with 400 rather than calling the upstream with model=\"\", which would only surface as a confusing 401/503.","triggerScenarios":"First-send race after endpoint setup where the picker showed a cached model but it was never persisted to the session row; endpoint's model cache is itself empty so recovery has nothing to pull; endpoint was deleted and re-created leaving the session modelless.","commonSituations":"User creates a chat immediately after adding an endpoint before models are fetched; a DB write failure when the model was chosen; sessions created via API without a model field.","solutions":["Open the model picker in the chat UI and explicitly select a model, then send again","Verify the endpoint has fetched its model list (check the endpoint's cached models in Settings)","For API callers, include a valid model when creating the session rather than leaving it blank"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (!session.model || !session.model.trim()) {\n  const models = await fetchEndpointModels(session.endpoint_id);\n  if (models.length) await setSessionModel(session.id, models[0]);\n  else { promptModelPick(); return; }\n}","typeGuard":"function hasModel(s: {model?: string | null}): boolean {\n  return typeof s.model === 'string' && s.model.trim().length > 0;\n}","tryCatchPattern":null,"preventionTips":["Block send until the session row actually has a model persisted","After adding an endpoint, wait for model discovery before enabling chat"],"tags":["model","configuration","chat","race-condition"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}