HKUDS/DeepTutor · error · EmbeddingProviderError
Embedding provider returned non-JSON response (content-type=
Error message
Embedding provider returned non-JSON response (content-type={content_type!r}): {exc}.{hint} What it means
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.
Source
Thrown at deeptutor/services/embedding/adapters/openai_compatible.py:319
content_type = response.headers.get("content-type", "")
body_preview = body_text.strip()[:200] or "<empty body>"
hint = ""
if not body_text.strip():
hint = (
" The response body was empty — the endpoint may "
"not support embeddings or the selected model "
"may not be an embedding model."
)
elif (
"text/html" in content_type.lower()
or body_preview.lstrip().startswith("<")
):
hint = (
" The response was HTML, not JSON — the URL is "
"likely wrong or the gateway does not expose "
"`/v1/embeddings`."
)
raise EmbeddingProviderError(
(
f"Embedding provider returned non-JSON response "
f"(content-type={content_type!r}): {exc}.{hint}"
),
status=response.status_code,
body=body_text,
model=model,
url=url,
provider="openai_compat",
) from exc
break
except httpx.TransportError as exc:
# httpx.TransportError covers all transient transport-layer
# failures: ConnectError, ReadError, WriteError, ConnectTimeout,
# ReadTimeout, WriteTimeout, PoolTimeout, RemoteProtocolError, etc.
# Retrying any of these with backoff is safe and obviates the
# need to keep extending an explicit allow-list.
last_exc = excView on GitHub (pinned to 3e82f13042)
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
Example fix
# before base_url = "https://my-gateway.example.com" # serves HTML index page # after base_url = "https://my-gateway.example.com/v1/embeddings"
Defensive patterns
Strategy: validation
Validate before calling
import httpx
async def endpoint_returns_json(base_url: str) -> bool:
r = await httpx.AsyncClient().get(base_url)
return "json" in r.headers.get("content-type", "") Type guard
null
Try / catch
try:
resp = await adapter.embed(req)
except EmbeddingProviderError as e:
if "non-JSON response" in str(e):
raise ConfigurationError(f"bad base_url (HTML response): {e.url}") from e
raise Prevention
- Prefer API hostnames/ports over web-UI URLs in base_url
- Verify /v1/embeddings exists via curl when adding a new gateway
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Cohere v1 API does not support multimodal `contents`. Use em
- Cohere model '{model_name}' does not support multimodal `con
- Cohere v2 does not support content type '{kind}'
- dashscope SDK not installed. Run `pip install dashscope` (or
- DashScope MultiModalEmbedding call failed: status={status_co
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/791af83fc802d7ba.
Report an issue: GitHub.