microsoft/semantic-kernel · error · ServiceResponseException
Upsert failed
Error message
Upsert failed
What it means
Raised in PostgresMemoryStore.upsert() when cur.fetchone() returns None after an INSERT ... RETURNING key. ServiceResponseException('Upsert failed') indicates the row was not returned despite the ON CONFLICT DO UPDATE ... RETURNING clause expecting a row. This is an unexpected DB response, not a normal not-found case.
Source
Thrown at python/semantic_kernel/connectors/memory_stores/postgres/postgres_memory_store.py:197
SET embedding = EXCLUDED.embedding,
metadata = EXCLUDED.metadata,
timestamp = EXCLUDED.timestamp
RETURNING key
"""
).format(
scm=Identifier(self._schema),
tbl=Identifier(collection_name),
),
(
record._id,
record.embedding.tolist(),
self.__serialize_metadata(record),
record._timestamp,
),
)
result = cur.fetchone()
if result is None:
raise ServiceResponseException("Upsert failed")
return result[0]
async def upsert_batch(self, collection_name: str, records: list[MemoryRecord]) -> list[str]:
"""Upserts a batch of records.
Args:
collection_name: The name of the collection to upsert the records into.
records: The records to upsert.
Returns:
List[str]: The unique database keys of the records.
"""
with self._connection_pool.connection() as conn, conn.cursor() as cur:
if not await self.__does_collection_exist(cur, collection_name):
raise ServiceResourceNotFoundError(f"Collection '{collection_name}' does not exist")
cur.nextset()
cur.executemany(
SQL(View on GitHub (pinned to c028a0c7dc)
Solutions
- Check DB logs for the actual statement error around the upsert timestamp.
- Verify the pgvector extension is installed and the embedding dimension matches the table's vector(N) column.
- Validate record.embedding length and that __serialize_metadata returns valid JSON before upsert.
- Recreate the connection pool if connections are stale; increase pool health checks.
Example fix
// before
await store.upsert("my_table", record)
// after
# validate before upsert
assert record.embedding.shape[0] == expected_dim
await store.upsert("my_table", record) Defensive patterns
Strategy: try-catch
Validate before calling
assert record.embedding is not None and record.embedding.shape[0] == expected_dim import json json.loads(json.dumps(record.__dict__)) # ensure metadata is JSON-serializable await store.upsert(collection_name, record)
Type guard
def is_valid_pg_record(record: MemoryRecord, dim: int) -> bool:
return record.embedding is not None and record.embedding.shape[0] == dim Try / catch
from semantic_kernel.exceptions import ServiceResponseException
try:
await store.upsert(collection_name, record)
except ServiceResponseException as e:
# 'Upsert failed' — check DB logs for the underlying statement error
logger.error("postgres upsert returned no row: %s", e)
raise Prevention
- Ensure pgvector is installed and the table vector(N) matches the embedding dim.
- Validate metadata serializes to valid JSONB before upsert.
- Recycle stale pool connections; monitor pool health.
When it happens
Trigger: The RETURNING clause produced no row — e.g., a DB-side rule rewrote the statement, a trigger suppressed the row, the connection was in a broken state, or a pgvector/serialization error left the statement non-returning. Most commonly a symptom of an underlying DB error surfacing as a missing return.
Common situations: Corrupt/timed-out connection from the pool; metadata serialization produced an invalid JSONB value; pgvector extension missing or dimension mismatch causing a silent statement failure; a BEFORE trigger returning NULL.
Related errors
- Collection '{collection_name}' does not exist
- Error upserting record: {upsert_response.message}
- Collection '{collection_name}' does not exist
- Failed to create Postgres settings.
- Batch upsert failed
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/c7c38a3d87a3ba3e.
Report an issue: GitHub.