MemPalace/mempalace · error · EmbeddingAPIError

Embedding API at {self._url} returned non-contiguous or dupl

Error message

Embedding API at {self._url} returned non-contiguous or duplicate 'index' values; cannot align embeddings with inputs

What it means

Raised by _vectors_from_response when, after sorting rows by 'index', the resulting indices are not exactly 0..n-1. The check exists because servers may return rows out of order (sorted first) but must not use absolute offsets (e.g. 5,6,7 for a second batch), duplicates, or gaps — positional alignment between texts and vectors would silently misassign embeddings, violating the 100%-recall promise. Alignment must be provably correct, so any deviation is fatal.

Source

Thrown at mempalace/embedding.py:604

                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"
            )
        try:
            arr = np.asarray([r["embedding"] for r in rows], dtype=np.float32)
        except (KeyError, TypeError, ValueError) as e:
            raise EmbeddingAPIError(
                f"Embedding API at {self._url} returned malformed embeddings: {e}"
            ) from e
        if arr.ndim != 2:
            raise EmbeddingAPIError(
                f"Embedding API at {self._url} returned non-vector embeddings (shape {arr.shape})"
            )
        # L2-normalize so cosine == dot product (collection uses
        # hnsw:space=cosine), matching EmbeddinggemmaONNX above.
        norms = np.linalg.norm(arr, axis=1, keepdims=True) + 1e-12
        return (arr / norms).tolist()

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Curl with a 3-text batch and verify each row has index 0, 1, 2 exactly (0-based, per request)
  2. Fix stubs to include "index": i for every row
  3. If a gateway re-batches, point mempalace directly at the model server or fix the gateway to renumber indices per request
  4. Confirm no rows are dropped mid-pipeline (dropped rows create gaps that fail this check)

Example fix

# gateway pseudo-code — before
resp['data'] = all_rows  # absolute indices from merged batch
# after
resp['data'] = [
    {**row, 'index': i}
    for i, row in enumerate(sorted(all_rows, key=lambda r: r['orig_pos']))
]
Defensive patterns

Strategy: validation

Validate before calling

resp = probe(url, model, inputs=["a", "b"])
idx = sorted(r.get("index") for r in resp["data"])
assert idx == list(range(len(resp["data"]))), f"indices {idx} not 0-based contiguous"

Type guard

def indices_are_contiguous(data) -> bool:
    rows = data.get("data", [])
    got = sorted(r.get("index", -1) for r in rows if isinstance(r, dict))
    return got == list(range(len(rows)))

Try / catch

try:
    vecs = ef(texts)
except EmbeddingAPIError as e:
    if "non-contiguous" in str(e):
        log.error("server uses absolute/duplicate indices; fix gateway re-indexing")
    raise

Prevention

When it happens

Trigger: A server that echoes the global input index instead of per-request 0-based index (common when a proxy batches multiple clients); duplicate index values from a server bug; missing rows combined with extras (e.g. indices [0,0,2] for n=3); a stub that omits 'index' entirely so all rows default to -1 after sorting.

Common situations: Aggregating gateways that re-index across concatenated batches; stub servers omitting the index field; homegrown servers copying absolute IDs from their internal queue into 'index'.

Related errors


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