microsoft/semantic-kernel · error · ServiceResponseException
Upsert failed
Error message
Upsert failed
What it means
Raised by QdrantMemoryStore.upsert() when the Qdrant client returns a result whose status is not UpdateStatus.COMPLETED. It is a ServiceResponseException; the upsert may have been acknowledged but not confirmed within the wait window. Note upsert() does not check collection existence first, so an absent collection usually surfaces as a client error before reaching this line.
Source
Thrown at python/semantic_kernel/connectors/memory_stores/qdrant/qdrant_memory_store.py:100
@override
async def does_collection_exist(self, collection_name: str) -> bool:
return self._qdrantclient.collection_exists(collection_name=collection_name)
@override
async def upsert(self, collection_name: str, record: MemoryRecord) -> str:
data_to_upsert = await self._convert_from_memory_record(
collection_name=collection_name,
record=record,
)
result = self._qdrantclient.upsert(
collection_name=collection_name,
points=[data_to_upsert],
)
if result.status == qdrant_models.UpdateStatus.COMPLETED:
return data_to_upsert.id
raise ServiceResponseException("Upsert failed")
@override
async def upsert_batch(self, collection_name: str, records: list[MemoryRecord]) -> list[str]:
tasks = []
for record in records:
tasks.append(
self._convert_from_memory_record(
collection_name=collection_name,
record=record,
)
)
data_to_upsert = await asyncio.gather(*tasks)
result = self._qdrantclient.upsert(
collection_name=collection_name,
points=data_to_upsert,
)View on GitHub (pinned to c028a0c7dc)
Solutions
- Retry the upsert with exponential backoff for transient non-COMPLETED statuses.
- Configure the QdrantClient for synchronous confirmation (so status reflects actual completion).
- Reduce batch/point size or warm the collection before bulk upserts.
- Catch ServiceResponseException, log result.status, and decide retry vs fail.
Example fix
// before
key = await store.upsert('mycol', record)
// after
from semantic_kernel.exceptions import ServiceResponseException
for attempt in range(3):
try:
key = await store.upsert('mycol', record)
break
except ServiceResponseException:
if attempt == 2: raise
await asyncio.sleep(2 ** attempt) Defensive patterns
Strategy: retry
Try / catch
from semantic_kernel.exceptions import ServiceResponseException
for attempt in range(3):
try:
key = await store.upsert(collection_name, record)
break
except ServiceResponseException:
if attempt == 2:
raise
await asyncio.sleep(2 ** attempt) Prevention
- Configure QdrantClient to wait for confirmation so a non-COMPLETED status is meaningful.
- Retry transient non-COMPLETED statuses with exponential backoff.
- Log the result.status value when this fires to distinguish timeout vs rejection.
When it happens
Trigger: Calling `await store.upsert(collection_name, record)` where self._qdrantclient.upsert(...) returns status ACKNOWLEDGED (or any non-COMPLETED value), e.g. when the client is configured with wait=False or the operation times out before confirmation.
Common situations: QdrantClient created without wait=True semantics; heavy load causing the operation to be acknowledged but not completed within the timeout; transient network issues; very large point payloads.
Related errors
- Batch upsert failed
- Delete failed
- Could not upsert messages.
- Collection '{collection_name}' does not exist
- Error upserting record: {upsert_response.message}
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/ef605e15e4616731.
Report an issue: GitHub.