{"record":{"id":"459945794bb99e59","repo":"odysseus-dev/odysseus","slug":"could-not-auto-detect-provider-pass-base-url-e-g","errorCode":null,"errorMessage":"Could not auto-detect provider. Pass base_url (e.g. 'https://api.deepseek.com/v1') or provider ('deepseek', 'openai', 'groq', etc.)","messagePattern":"Could not auto-detect provider\\. Pass base_url \\(e\\.g\\. 'https://api\\.deepseek\\.com/v1'\\) or provider \\('deepseek', 'openai', 'groq', etc\\.\\)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"routes/webhook/webhook_routes.py","lineNumber":296,"sourceCode":"\n        # --- Case 2: Direct API key + model (no pre-configured endpoint needed) ---\n        if not sess and body.api_key:\n            api_key = body.api_key.strip()\n            model = body.model or \"deepseek-chat\"\n\n            # Validate only token-supplied direct base_url; auto-resolved known-provider\n            # URLs are not subject to extra local/LAN blocking beyond existing provider logic.\n            direct_base_url = body.base_url.strip().rstrip(\"/\") if body.base_url else None\n            if direct_base_url:\n                try:\n                    base_url = validate_public_http_url(direct_base_url)\n                except ValueError as e:\n                    detail = str(e).replace(\"URL\", \"base_url\", 1)\n                    raise HTTPException(400, detail)\n            else:\n                base_url = _resolve_base_url(model, body.provider)\n            if not base_url:\n                raise HTTPException(400,\n                    \"Could not auto-detect provider. Pass base_url (e.g. 'https://api.deepseek.com/v1') \"\n                    \"or provider ('deepseek', 'openai', 'groq', etc.)\")\n            base_url = normalize_base(base_url)\n            endpoint_url = build_chat_url(base_url)\n\n            if not session_manager:\n                raise HTTPException(500, \"Session manager not available\")\n\n            sid = str(uuid.uuid4())\n            sess = session_manager.create_session(\n                session_id=sid, name=\"API Chat\", endpoint_url=endpoint_url,\n                model=model, owner=token_owner,\n            )\n            sess.headers = build_headers(api_key, base_url)\n            session_manager.save_sessions()\n            session_id = sid\n\n        # --- Case 3: Fall back to first configured ModelEndpoint ---","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/webhook/webhook_routes.py#L278-L314","documentation":"HTTP 400 from POST /v1/chat: no base_url was supplied and _resolve_base_url(model, provider) could not map the request to a known provider. Resolution keys off the model name prefix or an explicit provider string against KNOWN_PROVIDERS (deepseek, openai, groq, ...).","triggerScenarios":"Passing api_key + an unrecognized model (e.g. 'llama-3-70b') with no base_url and no provider; passing a provider string not in KNOWN_PROVIDERS (typo like 'opena1'); provider given as None and model name doesn't start with any known prefix.","commonSituations":"Using a third-party OpenAI-compatible aggregator (OpenRouter, Together) whose model names don't match known prefixes; new model names the resolver's prefix table doesn't know yet.","solutions":["Add an explicit provider field matching a KNOWN_PROVIDERS key (e.g. 'deepseek', 'openai', 'groq')","Or supply a public base_url explicitly (see the SSRF constraints of error 929)","Or configure a ModelEndpoint in Admin and call with no api_key (Case 3 fallback)"],"exampleFix":"// before\n{\"message\":\"hi\",\"api_key\":\"sk-...\",\"model\":\"llama-3-70b\"}\n\n// after\n{\"message\":\"hi\",\"api_key\":\"sk-...\",\"model\":\"llama-3-70b\",\"provider\":\"groq\"}","handlingStrategy":"validation","validationCode":"KNOWN = {\"deepseek\", \"openai\", \"groq\"}  # keep in sync with KNOWN_PROVIDERS\nif not base_url and (provider not in KNOWN and not model.startswith(tuple(KNOWN))):\n    require_explicit_provider_or_base_url()","typeGuard":null,"tryCatchPattern":"if resp.status_code == 400 and 'auto-detect provider' in detail:\n    retry_with(provider=guess_provider(model), base_url=None)","preventionTips":["Always send an explicit provider with non-standard model names","Or configure a ModelEndpoint in Admin and skip per-request api_key entirely"],"tags":["provider-resolution","chat","http-400","config"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}