{"record":{"id":"a6b711198ff97371","repo":"cocoindex-io/cocoindex","slug":"litellm-embedding-response-has-len-data-items-f","errorCode":null,"errorMessage":"litellm embedding response has {len(data)} items for {n} inputs","messagePattern":"litellm embedding response has (.+?) items for (.+?) inputs","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/cocoindex/ops/litellm.py","lineNumber":181,"sourceCode":"            multiplier=2.0,\n            max_delay=_EMBEDDING_RETRY_MAX_BACKOFF_SECONDS,\n        ),\n        bound_attempt=True,\n        operation_name=operation_name,\n    )\n\n\ndef _aligned_embeddings(data: list[_Any], n: int) -> list[_NDArray[_np.float32]]:\n    \"\"\"Map embedding response items back to the ``n`` inputs they embed.\n\n    Items carrying an ``index`` are placed by it; if no item carries one\n    (missing or ``None``), the response is taken positionally. Mixing the two,\n    or an index set that is not a permutation of ``0..n-1``, raises so a\n    misordered response fails loudly instead of silently misaligning\n    embeddings with their texts.\n    \"\"\"\n    if len(data) != n:\n        raise RuntimeError(\n            f\"litellm embedding response has {len(data)} items for {n} inputs\"\n        )\n    out: list[_NDArray[_np.float32] | None] = [None] * n\n    indexed = n > 0 and data[0].get(\"index\") is not None\n    for pos, item in enumerate(data):\n        index = item.get(\"index\")\n        if (index is not None) != indexed:\n            raise RuntimeError(\n                \"litellm embedding response mixes items with and without `index`\"\n            )\n        if not indexed:\n            index = pos\n        elif type(index) is not int or not 0 <= index < n or out[index] is not None:\n            raise RuntimeError(\n                \"litellm embedding response indices are not a permutation of \"\n                f\"0..{n - 1}: got {[item.get('index') for item in data]}\"\n            )\n        out[index] = _np.array(item[\"embedding\"], dtype=_np.float32)","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/ops/litellm.py#L163-L199","documentation":"Raised by `_aligned_embeddings` when a litellm embedding response contains a different number of items than the number of input texts sent. The library aligns each returned embedding to its input text and cannot do so safely when counts differ, so it fails loudly rather than silently misaligning embeddings.","triggerScenarios":"Calling a litellm-based embedding op where the provider (or litellm proxy) returns fewer or more embedding items in `data` than the number of input strings, e.g. dropped inputs, provider truncation, or batching bugs.","commonSituations":"Provider-side truncation on very large batches; a litellm proxy aggregating/rewriting responses; using a model/route that returns a partial response; API version changes altering the response shape.","solutions":["Reduce the batch size of texts sent per embedding request and retry.","Inspect the raw litellm response (log it) to see whether the provider actually returned fewer items.","Check the provider/model route for known response-shape issues, or switch provider/model.","Upgrade litellm and cocoindex if a recent version change altered the response format."],"exampleFix":"// before\nembeddings = embed_op.embed(texts)  # texts has 500 items, provider truncates\n// after\nfor chunk in _chunks(texts, 64):\n    embeddings.extend(embed_op.embed(chunk))","handlingStrategy":"retry","validationCode":"if isinstance(resp, dict) and len(resp.get(\"data\", [])) != len(texts):\n    raise ValueError(f\"provider returned {len(resp.get('data', []))} items for {len(texts)} inputs\")","typeGuard":null,"tryCatchPattern":"try:\n    embs = embed_op.embed(texts)\nexcept RuntimeError as e:\n    if 'embedding response has' in str(e):\n        embs = [embed_op.embed([t])[0] for t in texts]  # fall back to per-item calls\n    else:\n        raise","preventionTips":["Keep embedding batches modest (e.g. <=128) to avoid provider truncation.","Log raw responses once per new provider/model to verify shape before production use.","Pin litellm and provider SDK versions; re-verify after upgrades."],"tags":["python","embeddings","litellm","response-shape"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b","analyzedAt":"2026-09-08T15:59:19.997Z","contentChangedAt":"2026-09-08T15:59:19.997Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}