BerriAI/litellm · error · Exception

/v1/embeddings route returned None Embeddings.

Error message

/v1/embeddings route returned None Embeddings.

What it means

Second half of the async multimodal embedding flow: after a successful /v1/embeddings (text) call, LiteLLM checks response.data and raises '/v1/embeddings route returned None Embeddings.' if the parsed data array is None. Like its image twin, the HTTP call succeeded but no vectors were extracted — usually bad input or a response-shape mismatch.

Source

Thrown at litellm/llms/azure_ai/embed/handler.py:185

            if image_embedding_responses is None:
                raise Exception("/image/embeddings route returned None Embeddings.")

        if v1_embeddings_request["input"]:
            response: Final[EmbeddingResponse] = await super().embedding(
                model=model,
                input=input,
                timeout=timeout,
                logging_obj=logging_obj,
                model_response=model_response,
                optional_params=optional_params,
                api_key=api_key,
                api_base=api_base,
                client=client,
                aembedding=True,
            )
            text_embedding_responses = response.data
            if text_embedding_responses is None:
                raise Exception("/v1/embeddings route returned None Embeddings.")

        return self._process_response(
            image_embedding_responses=image_embedding_responses,
            text_embedding_responses=text_embedding_responses,
            image_embeddings_idx=image_embeddings_idx,
            model_response=model_response,
            input=input,
        )

    def embedding(
        self,
        model: str,
        input: list,
        timeout: float,
        logging_obj,
        model_response: EmbeddingResponse,
        optional_params: dict,
        api_key: str | None = None,

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Log the input array right before the call — hunt for empty/None/non-string entries and filter them.
  2. Inspect the raw /v1/embeddings response for one input via curl to see whether data is absent upstream or lost in parsing.
  3. If raw data exists but litellm yields None, upgrade litellm.
  4. Send text and images as separate, well-formed lists rather than relying on the combined route to sort them.

Example fix

# before
resp = await litellm.aembedding(model='azure_ai/mm-embed', input=texts_and_images)

# after
texts = [t for t in inputs if isinstance(t, str) and t.strip()]
images = [i for i in inputs if is_image(i)]
resp = await litellm.aembedding(model='azure_ai/mm-embed', input=texts + images)
Defensive patterns

Strategy: validation

Validate before calling

def clean_text_inputs(inputs: list) -> list[str]:
    cleaned = [t for t in inputs if isinstance(t, str) and t.strip()]
    if not cleaned:
        raise ValueError('no non-empty text inputs for /v1/embeddings')
    return cleaned

Try / catch

try:
    resp = await litellm.aembedding(model='azure_ai/mm-embed', input=clean_text_inputs(texts))
except Exception as e:
    if '/v1/embeddings route returned None' in str(e):
        logger.error('empty embedding data for inputs=%r', texts)
        return fallback_embedding()  # or skip batch
    raise

Prevention

When it happens

Trigger: aembedding() where the text part of the input is malformed (empty strings, None entries) so Azure returns 200 with no data; or the azure_ai response parser failing on an unexpected payload shape; text-only requests reaching this combined handler with the text list unexpectedly empty-but-truthy.

Common situations: Mixing image and text inputs and a filtering step leaves whitespace-only strings; upstream producer sends dicts where strings were expected; litellm/azure schema drift after preview api-version change.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/b6f0c04407494ecc. Report an issue: GitHub.