HKUDS/DeepTutor · error · ValueError

Embedding provider returned error payload: {err}

Error message

Embedding provider returned error payload: {err}

What it means

The HTTP request itself succeeded (often HTTP 200), but the JSON body contains a top-level "error" object instead of embedding vectors. Many OpenAI-compatible gateways report auth failures, invalid model names, or quota exhaustion this way instead of using an HTTP error status, so the adapter checks for it after parsing.

Source

Thrown at deeptutor/services/embedding/adapters/openai_compatible.py:99

            raise ValueError(f"Embedding response is not a JSON object: type={type(data).__name__}")

        # Some providers return HTTP 200 with {"error": ...} payload.
        if "error" in data:
            err = data.get("error")
            if isinstance(err, dict):
                msg = (
                    err.get("message")
                    or err.get("msg")
                    or err.get("detail")
                    or json.dumps(err, ensure_ascii=False)
                )
                code = err.get("code")
                etype = err.get("type")
                raise ValueError(
                    f"Embedding provider returned error payload: "
                    f"message={msg}, code={code}, type={etype}"
                )
            raise ValueError(f"Embedding provider returned error payload: {err}")

        candidates = []
        # Standard OpenAI schema
        if isinstance(data.get("data"), list):
            candidates.append(data["data"])
        # Common proxy schema
        if isinstance(data.get("embeddings"), list):
            candidates.append(data["embeddings"])
        # Ollama /api/embeddings returns singular "embedding" as a flat vector
        if isinstance(data.get("embedding"), list):
            emb = data["embedding"]
            if emb and isinstance(emb[0], (int, float)):
                candidates.append([emb])
            else:
                candidates.append(emb)
        # Nested result/output variants
        result = data.get("result")
        if isinstance(result, dict):

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Read the embedded message= in the ValueError — it is the provider's own diagnostic (model name, auth, quota)
  2. Fix the model id in the embedding binding to one the gateway actually serves
  3. Verify the API key is valid and has embedding quota; test with curl against the same base_url
  4. If the gateway consistently returns 200-with-error, ask it to return proper HTTP status codes or switch to one that does

Example fix

// before
model = "text-embeddings-3-small"  # typo, gateway returns {"error": {...}}
// after
model = "text-embedding-3-small"
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try:
    resp = await adapter.embed(req)
except ValueError as e:
    if "error payload" in str(e):
        # provider-side error surfaced in a 200 body; log and surface to user / alert
        log_provider_error(e)
    raise

Prevention

When it happens

Trigger: POST to base_url embeddings endpoint returns 200/4xx with body like {"error": {"message": "model not found", "code": ..., "type": ...}} — e.g. wrong model name on a proxy, expired API key, or exhausted quota on a gateway that wraps errors in a 200.

Common situations: Typo'd model id on LiteLLM/Ollama/OpenRouter-style proxies; key rotated/revoked; free-tier quota exhausted; gateway downgraded the error into a 200 response.

Related errors


AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27). Data as JSON: /api/errors/5ccac4442ec70c44. Report an issue: GitHub.