{"record":{"id":"ae5a6afb32dc1f55","repo":"MemPalace/mempalace","slug":"embedding-api-at-self-url-returned-malformed-em","errorCode":null,"errorMessage":"Embedding API at {self._url} returned malformed embeddings: {e}","messagePattern":"Embedding API at (.+?) returned malformed embeddings: (.+?)","errorType":"exception","errorClass":"EmbeddingAPIError","httpStatus":null,"severity":"error","filePath":"mempalace/embedding.py","lineNumber":611,"sourceCode":"        # require the indices to be exactly 0..n-1 so positional alignment is\n        # provably correct (a server using absolute or duplicate indices would\n        # otherwise pass the count check yet map vectors to the wrong texts).\n        try:\n            rows = sorted(rows, key=lambda d: d.get(\"index\", -1))\n            indices = [r.get(\"index\") for r in rows]\n        except AttributeError as e:\n            raise EmbeddingAPIError(\n                f\"Embedding API at {self._url} returned non-object rows: {e}\"\n            ) from e\n        if indices != list(range(n)):\n            raise EmbeddingAPIError(\n                f\"Embedding API at {self._url} returned non-contiguous or duplicate \"\n                f\"'index' values; cannot align embeddings with inputs\"\n            )\n        try:\n            arr = np.asarray([r[\"embedding\"] for r in rows], dtype=np.float32)\n        except (KeyError, TypeError, ValueError) as e:\n            raise EmbeddingAPIError(\n                f\"Embedding API at {self._url} returned malformed embeddings: {e}\"\n            ) from e\n        if arr.ndim != 2:\n            raise EmbeddingAPIError(\n                f\"Embedding API at {self._url} returned non-vector embeddings (shape {arr.shape})\"\n            )\n        # L2-normalize so cosine == dot product (collection uses\n        # hnsw:space=cosine), matching EmbeddinggemmaONNX above.\n        norms = np.linalg.norm(arr, axis=1, keepdims=True) + 1e-12\n        return (arr / norms).tolist()\n\n\ndef get_embedding_function(device: Optional[str] = None, model: Optional[str] = None):\n    \"\"\"Return a cached embedding function for the requested device + model.\n\n    ``device=None`` reads :attr:`MempalaceConfig.embedding_device`;\n    ``model=None`` reads :attr:`MempalaceConfig.embedding_model`.\n    The returned function is shared across calls with the same resolved","sourceCodeStart":593,"sourceCodeEnd":629,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/embedding.py#L593-L629","documentation":"Raised by _vectors_from_response when building np.asarray([r['embedding'] for r in rows], dtype=np.float32) fails with KeyError (a row missing the 'embedding' key), TypeError (embedding present but not array-like, e.g. a dict), or ValueError (strings or ragged lists that cannot become a uniform float32 array). This blocks non-numeric or ragged payloads — including base64-encoded embeddings — before they can corrupt the vector store.","triggerScenarios":"A server returns embeddings as base64 strings (the exact case the caller's encoding_format='float' request was meant to prevent); a row omits 'embedding'; vectors of differing lengths across rows (ragged); embedding values as strings ('0.14').","commonSituations":"A server that ignores encoding_format and defaults to base64; older servers returning 'embedding' under a different key ('vector', 'values'); quantized servers returning mixed-dimension rows; middleware converting numbers to strings.","solutions":["Confirm the server honors encoding_format='float' in the request and returns plain float arrays in each row's 'embedding' field","Update the embedding server to a version that respects the OpenAI encoding_format parameter, or disable its base64 default","Verify all vectors share the same dimensionality as the model's output","Curl one request and inspect the raw JSON of a single data row"],"exampleFix":"# server — before\ne = base64.b64encode(vec.astype(np.float32).tobytes()).decode()\nreturn {\"data\": [{\"index\": i, \"embedding\": e}]}\n# after\nreturn {\"data\": [{\"index\": i, \"embedding\": vec.tolist()}]}","handlingStrategy":"validation","validationCode":"import base64\nrow = resp[\"data\"][0][\"embedding\"]\nassert not isinstance(row, str), \"server returned base64 despite encoding_format=float\"\nassert all(isinstance(v, (int, float)) for v in row), \"non-numeric embedding values\"","typeGuard":"def embeddings_are_numeric(data) -> bool:\n    try:\n        rows = data[\"data\"]\n        return all(isinstance(r[\"embedding\"], list)\n                   and all(isinstance(v, (int, float)) for v in r[\"embedding\"])\n                   for r in rows)\n    except (KeyError, TypeError):\n        return False","tryCatchPattern":"try:\n    vecs = ef(texts)\nexcept EmbeddingAPIError as e:\n    if \"malformed embeddings\" in str(e):\n        log.error(\"server ignored encoding_format=float (likely base64); fix server or upgrade it\")\n    raise","preventionTips":["Use a server version that honors the encoding_format parameter","Check one raw response with curl before wiring a new embedding backend","Keep embedding dimensionality constant across your deployment"],"tags":["embedding","api","validation","numpy","base64"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}