MemPalace/mempalace · error · EmbeddingAPIError

Embedding API at {self._url} returned {len(rows)} embeddings

Error message

Embedding API at {self._url} returned {len(rows)} embeddings for {n} inputs

What it means

Raised by _vectors_from_response when the 'data' array length does not equal the number of inputs sent in the batch (n). The client batches texts in groups of _EF_API_BATCH and expects exactly one embedding per input; a server that silently drops, truncates, or duplicates rows breaks the positional text-to-vector mapping, so the mismatch is treated as a hard failure rather than best-effort alignment.

Source

Thrown at mempalace/embedding.py:589

        that aren't the contiguous ``0..n-1`` batch positions (sorting then
        zipping positionally would otherwise misalign vectors with texts), and
        malformed / ragged / base64 embedding payloads. All failures raise
        :class:`EmbeddingAPIError` naming the endpoint rather than a cryptic
        numpy error — a silent wrong result would break the 100%-recall promise.
        """
        import numpy as np

        if not isinstance(data, dict):
            raise EmbeddingAPIError(
                f"Embedding API at {self._url} returned a non-object response: {data}"
            )
        rows = data.get("data")
        if not isinstance(rows, list):
            raise EmbeddingAPIError(
                f"Embedding API at {self._url} returned no 'data' array: {data.get('error', data)}"
            )
        if len(rows) != n:
            raise EmbeddingAPIError(
                f"Embedding API at {self._url} returned {len(rows)} embeddings for {n} inputs"
            )
        # The endpoint may return rows out of order — sort by index, then
        # require the indices to be exactly 0..n-1 so positional alignment is
        # provably correct (a server using absolute or duplicate indices would
        # otherwise pass the count check yet map vectors to the wrong texts).
        try:
            rows = sorted(rows, key=lambda d: d.get("index", -1))
            indices = [r.get("index") for r in rows]
        except AttributeError as e:
            raise EmbeddingAPIError(
                f"Embedding API at {self._url} returned non-object rows: {e}"
            ) from e
        if indices != list(range(n)):
            raise EmbeddingAPIError(
                f"Embedding API at {self._url} returned non-contiguous or duplicate "
                f"'index' values; cannot align embeddings with inputs"
            )

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Check the message numbers (e.g. 'returned 1 embeddings for 8 inputs') — a 1-vs-n result usually means the server ignored the batch and embedded only the first text
  2. Update or switch the embedding server to one that conforms to the OpenAI /v1/embeddings contract (one row per input)
  3. If hosting your own server, verify it maps input array -> output array 1:1
  4. Report a server-side max-batch limit if truncation is the cause; keep batches under it via the server config

Example fix

# stub server — before
return {"data": [{"index": 0, "embedding": embed(texts[0])}]}
# after
return {"data": [{"index": i, "embedding": embed(t)} for i, t in enumerate(texts)]}
Defensive patterns

Strategy: validation

Validate before calling

resp = probe(url, model, inputs=["a", "b", "c"])
assert len(resp["data"]) == 3, f"server returned {len(resp['data'])} rows for 3 inputs — not 1:1"

Type guard

def is_one_to_one(data, n: int) -> bool:
    return isinstance(data.get("data"), list) and len(data["data"]) == n

Try / catch

try:
    vecs = ef(texts)
except EmbeddingAPIError as e:
    if "embeddings for" in str(e):
        log.error("embedding server is not 1:1 per input; fix server before ingest")
    raise  # never retry: a wrong count means wrong alignment

Prevention

When it happens

Trigger: A server that caps response size, deduplicates identical input texts and returns fewer embeddings, streams partial results on error, or applies its own max batch limit smaller than mempalace's _EF_API_BATCH and truncates instead of erroring.

Common situations: Batch contains many duplicate strings and the server dedupes; a proxy truncates large JSON responses; llama.cpp server limits n_batch inputs; a stub returns a fixed single embedding regardless of input count.

Related errors


AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15). Data as JSON: /api/errors/67e6d43041d04fa0. Report an issue: GitHub.