{"record":{"id":"87c19e6928103c89","repo":"unslothai/unsloth","slug":"embedder-returned-len-items-vectors-for-len-ch","errorCode":null,"errorMessage":"embedder returned {len(items)} vectors for {len(chunk)} inputs","messagePattern":"embedder returned (.+?) vectors for (.+?) inputs","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"studio/backend/core/rag/embed_llama_server.py","lineNumber":752,"sourceCode":"        model_name = None,\n        normalize = True,\n    ):\n        \"\"\"Embed texts -> (N, dim) float32. ``model_name`` is ignored (the GGUF is\n        fixed by config). Normalizes in Python to match the ST backend.\"\"\"\n        n = len(texts)\n        if n == 0:\n            return np.zeros((0, self.dim()), dtype = np.float32)\n        rows: list[list[float]] = []\n        batch = max(1, config.EMBED_BATCH)\n        for start in range(0, n, batch):\n            chunk = list(texts[start : start + batch])\n            data = self._post(\n                \"/v1/embeddings\",\n                {\"input\": chunk, \"model\": \"embedding\", \"encoding_format\": \"float\"},\n            )\n            items = data.get(\"data\", [])\n            if len(items) != len(chunk):\n                raise RuntimeError(\n                    f\"embedder returned {len(items)} vectors for {len(chunk)} inputs\"\n                )\n            # OpenAI spec lets the server reorder; sort back by index.\n            items = sorted(items, key = lambda d: d.get(\"index\", 0))\n            rows.extend(d[\"embedding\"] for d in items)\n        arr = np.asarray(rows, dtype = np.float32)\n        if arr.ndim != 2:\n            raise RuntimeError(f\"embedder returned ragged vectors: shape {arr.shape}\")\n        if normalize:\n            norms = np.linalg.norm(arr, axis = 1, keepdims = True)\n            norms[norms == 0] = 1.0\n            arr = arr / norms\n        return arr\n\n    def dim(self, *, model_name = None) -> int:\n        \"\"\"Embedding width, probed via a 1-text encode and cached per model\n        (_resolve_model_path clears it when the effective repo changes).\n        Unlocked: concurrent probes are benign, and locking would deadlock when","sourceCodeStart":734,"sourceCodeEnd":770,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/rag/embed_llama_server.py#L734-L770","documentation":"Raised during encode() when the /v1/embeddings response contains a different number of embedding objects than texts sent in the batch. The backend requires a strict 1:1 correspondence before it sorts by index and stacks the vectors, so a mismatched count is treated as a protocol violation rather than silently producing misaligned rows. It guards against server bugs or truncated responses corrupting the vector store.","triggerScenarios":"Calling encode() with a batch where llama-server drops or duplicates items (server bug, streaming truncation, non-OpenAI-compliant server behind the URL); a server that errors on empty-string inputs and omits them from the response; EMBED_BATCH exceeding a server-side limit that silently caps response items.","commonSituations":"Pointing the backend at a proxy or alternative OpenAI-compatible server that implements /v1/embeddings loosely; llama.cpp server versions with batch embedding bugs; documents that reduce to empty strings after preprocessing.","solutions":["Log len(chunk) and len(items) at the failure to see whether the server is dropping, capping, or adding items.","Filter or pad empty/whitespace-only strings out of texts before calling encode().","Lower EMBED_BATCH below any server-side batch limit.","Pin/upgrade llama.cpp to a version with a conformant /v1/embeddings implementation.","If using a custom server, verify its response against the OpenAI embeddings schema (data[i].index present, one item per input)."],"exampleFix":"# before\ntexts = [chunk.page_content for chunk in chunks]  # may contain \"\"\n\n# after\ntexts = [t if t.strip() else \" \" for t in (c.page_content for c in chunks)]  # no empty inputs","handlingStrategy":"validation","validationCode":"def sanitize_texts(texts: list[str]) -> list[str]:\n    # no empty/whitespace inputs; servers may drop them and break the 1:1 count\n    return [t if t.strip() else \" \" for t in texts]","typeGuard":null,"tryCatchPattern":"try:\n    arr = backend.encode(chunk_texts)\nexcept RuntimeError as e:\n    if \"vectors for\" in str(e) and \"inputs\" in str(e):\n        # retry one-by-one to isolate the offending text, or shrink batch\n        arr = np.stack([backend.encode([t])[0] for t in chunk_texts])\n    else:\n        raise","preventionTips":["Never send empty strings to /v1/embeddings; substitute a single space.","Keep EMBED_BATCH below the server's documented per-request item limit.","Pin a llama.cpp version whose /v1/embeddings you have verified returns exactly N items."],"tags":["embeddings","protocol","validation","batching"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}