{"record":{"id":"791af83fc802d7ba","repo":"HKUDS/DeepTutor","slug":"embedding-provider-returned-non-json-response-con","errorCode":null,"errorMessage":"Embedding provider returned non-JSON response (content-type={content_type!r}): {exc}.{hint}","messagePattern":"Embedding provider returned non-JSON response \\(content-type=(.+?)\\): (.+?)\\.(.+?)","errorType":"http","errorClass":"EmbeddingProviderError","httpStatus":null,"severity":"error","filePath":"deeptutor/services/embedding/adapters/openai_compatible.py","lineNumber":319,"sourceCode":"                        content_type = response.headers.get(\"content-type\", \"\")\n                        body_preview = body_text.strip()[:200] or \"<empty body>\"\n                        hint = \"\"\n                        if not body_text.strip():\n                            hint = (\n                                \" The response body was empty — the endpoint may \"\n                                \"not support embeddings or the selected model \"\n                                \"may not be an embedding model.\"\n                            )\n                        elif (\n                            \"text/html\" in content_type.lower()\n                            or body_preview.lstrip().startswith(\"<\")\n                        ):\n                            hint = (\n                                \" The response was HTML, not JSON — the URL is \"\n                                \"likely wrong or the gateway does not expose \"\n                                \"`/v1/embeddings`.\"\n                            )\n                        raise EmbeddingProviderError(\n                            (\n                                f\"Embedding provider returned non-JSON response \"\n                                f\"(content-type={content_type!r}): {exc}.{hint}\"\n                            ),\n                            status=response.status_code,\n                            body=body_text,\n                            model=model,\n                            url=url,\n                            provider=\"openai_compat\",\n                        ) from exc\n                break\n            except httpx.TransportError as exc:\n                # httpx.TransportError covers all transient transport-layer\n                # failures: ConnectError, ReadError, WriteError, ConnectTimeout,\n                # ReadTimeout, WriteTimeout, PoolTimeout, RemoteProtocolError, etc.\n                # Retrying any of these with backoff is safe and obviates the\n                # need to keep extending an explicit allow-list.\n                last_exc = exc","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/embedding/adapters/openai_compatible.py#L301-L337","documentation":"The endpoint returned a 2xx response whose body is not JSON, so response.json() raised. This almost always means the URL/model pairing is wrong: the gateway served an HTML error page, a login page, or an empty body instead of embeddings JSON.","triggerScenarios":"base_url points at a web UI or a host without /v1/embeddings (HTML 200 response); reverse proxy serves an SPA index.html for unknown paths; empty body when the selected model is not an embedding model.","commonSituations":"Using the frontend URL instead of the API URL (port 3000 vs 8000); missing /v1/embeddings path suffix; gateway requires auth and redirects to an HTML login page; typo in hostname serving a parked page.","solutions":["Follow the hint in the message: if HTML, fix base_url to the real API embeddings endpoint (include /v1/embeddings)","If the body was empty, verify the selected model is actually an embedding model","Confirm the gateway exposes the embeddings route (curl it directly)","Check for proxy/redirect layers stripping the path"],"exampleFix":"# before\nbase_url = \"https://my-gateway.example.com\"  # serves HTML index page\n# after\nbase_url = \"https://my-gateway.example.com/v1/embeddings\"","handlingStrategy":"validation","validationCode":"import httpx\n\nasync def endpoint_returns_json(base_url: str) -> bool:\n    r = await httpx.AsyncClient().get(base_url)\n    return \"json\" in r.headers.get(\"content-type\", \"\")","typeGuard":"null","tryCatchPattern":"try:\n    resp = await adapter.embed(req)\nexcept EmbeddingProviderError as e:\n    if \"non-JSON response\" in str(e):\n        raise ConfigurationError(f\"bad base_url (HTML response): {e.url}\") from e\n    raise","preventionTips":["Prefer API hostnames/ports over web-UI URLs in base_url","Verify /v1/embeddings exists via curl when adding a new gateway"],"tags":["non-json-response","html-response","wrong-url","embeddings"],"backgroundTag":"endpoint-returns-html-instead-of-json","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}