microsoft/semantic-kernel · error · VectorStoreOperationException
This index (of type {type(self.indexes[vector_field.name])})
Error message
This index (of type {type(self.indexes[vector_field.name])}) requires training, which is not supported. To train the index, use <collection>.indexes[{vector_field.name}].train, see faiss docs for more details. What it means
FaissCollection upserts each record's vector into a faiss.Index keyed by the vector field. Some faiss index families (IVF, PQ, IVFPQ, SQ, some HNSW variants) need a separate training pass before they accept vectors; the connector never trains for you. At _inner_upsert it checks index.is_trained and raises VectorStoreOperationException if the index is still untrained, telling you to call .train() yourself. This is the runtime safety net: _create_indexes already rejects untrained indexes passed via the index/indexes constructor args, so this fires only when an index became untrained after collection setup (e.g. you assigned collection.indexes[name] directly).
Source
Thrown at python/semantic_kernel/connectors/faiss.py:170
For more advanced scenario's you can create your own indexes and pass them in here.
This includes indexes that need training, or GPU-based indexes, since you would also
need to build the faiss package for use with GPU's yourself.
Args:
index: The index to use, this can be used when there is only one vector field.
indexes: A dictionary of indexes, the key is the name of the vector field.
kwargs: Additional arguments.
"""
self._create_indexes(index=index, indexes=indexes)
@override
async def _inner_upsert(self, records: Sequence[Any], **kwargs: Any) -> Sequence[TKey]:
"""Upsert records."""
for vector_field in self.definition.vector_fields:
vectors_to_add = [record.get(vector_field.storage_name or vector_field.name) for record in records]
vectors = np.array(vectors_to_add, dtype=np.float32)
if not self.indexes[vector_field.name].is_trained:
raise VectorStoreOperationException(
f"This index (of type {type(self.indexes[vector_field.name])}) requires training, "
"which is not supported. To train the index, "
f"use <collection>.indexes[{vector_field.name}].train, "
"see faiss docs for more details."
)
self.indexes[vector_field.name].add(vectors) # type: ignore
start = len(self.indexes_key_map[vector_field.name])
for i, record in enumerate(records):
key = record[self.definition.key_field.name]
self.indexes_key_map[vector_field.name][key] = start + i
return await super()._inner_upsert(records, **kwargs)
@override
async def _inner_delete(self, keys: Sequence[TKey], **kwargs: Any) -> None:
for key in keys:
for vector_field in self.definition.vector_field_names:
if key in self.indexes_key_map[vector_field]:
vector_index = self.indexes_key_map[vector_field][key]View on GitHub (pinned to c028a0c7dc)
Solutions
- Train the index before upsert: gather a representative numpy float32 array of vectors (at least nlist rows for IVF) and call collection.indexes[vector_field_name].train(training_vectors).
- Pass a pre-trained index via indexes={'field': idx} at construction / ensure_collection_exists so the connector's trained check validates it up front.
- Use an always-trained flat index (IndexFlatL2 / IndexFlatIP) by not supplying a custom index; _create_index creates one automatically for IndexKind.FLAT/DEFAULT.
Example fix
# before import faiss quantizer = faiss.IndexFlatL2(128) idx = faiss.IndexIVFFlat(quantizer, 128, 32) collection.indexes['vec'] = idx # not trained -> upsert raises [1300] await collection.upsert(records) # after training = np.array(all_vectors, dtype=np.float32) idx.train(training) # IVF/PQ indexes need this idx.add(training) # optional: seed with training data collection.indexes['vec'] = idx await collection.upsert(records)
Defensive patterns
Strategy: validation
Validate before calling
import numpy as np
def assert_indexes_trained(collection, n_training=None):
for vf in collection.definition.vector_fields:
idx = collection.indexes.get(vf.name)
if idx is None:
continue
if not idx.is_trained:
if n_training is None:
raise RuntimeError(f"index '{vf.name}' is not trained; pass training vectors")
training = np.asarray(training_vectors_for(vf), dtype=np.float32)
idx.train(training)
# now safe to upsert Type guard
def is_index_ready(idx) -> bool:
# faiss indexes expose is_trained; flat indexes are always trained
return getattr(idx, 'is_trained', True) Try / catch
from semantic_kernel.exceptions import VectorStoreOperationException
try:
await collection.upsert(records)
except VectorStoreOperationException as ex:
if 'requires training' in str(ex):
collection.indexes[field_name].train(training_vectors)
await collection.upsert(records)
else:
raise Prevention
- Train IVF/PQ/SQ indexes on a representative vector sample before first upsert.
- Prefer auto-created flat indexes unless you specifically need IVF/PQ.
- If you must supply a custom index, pass it via ensure_collection_exists(indexes=...) so the trained check runs up front.
When it happens
Trigger: Calling await collection.upsert(records) when the index for a vector field is an untrained faiss index such as faiss.IndexIVFFlat, IndexIVFPQ, IndexPQ, or IndexSQ. Reproduce by building an IVF index, assigning collection.indexes['vec'] = faiss.IndexIVFFlat(quantizer, dim, nlist) without calling .train(training_vectors), then upserting.
Common situations: Switching from a flat index to IVF/PQ for scale; copying a faiss tutorial snippet that constructs an IVF index; manually replacing collection.indexes[...] after ensure_collection_exists so the construction-time trained check is bypassed; GPU/quantizer indexes that require training.
Related errors
- AI Embedding Service type '{appConfig.RagConfig.AIEmbeddingS
- The vector store must have an embedding generator.
- Index kind {field.index_kind} is not supported.
- Distance function {field.distance_function} is not supported
- Distance function {field.distance_function} is not supported
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/38f3cf47fe543e2e.
Report an issue: GitHub.