{"record":{"id":"38f3cf47fe543e2e","repo":"microsoft/semantic-kernel","slug":"this-index-of-type-type-self-indexes-vector-fiel","errorCode":null,"errorMessage":"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.","messagePattern":"This index \\(of type (.+?)\\) requires training, which is not supported\\. To train the index, use <collection>\\.indexes\\[(.+?)\\]\\.train, see faiss docs for more details\\.","errorType":"exception","errorClass":"VectorStoreOperationException","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/connectors/faiss.py","lineNumber":170,"sourceCode":"        For more advanced scenario's you can create your own indexes and pass them in here.\n        This includes indexes that need training, or GPU-based indexes, since you would also\n        need to build the faiss package for use with GPU's yourself.\n\n        Args:\n            index: The index to use, this can be used when there is only one vector field.\n            indexes: A dictionary of indexes, the key is the name of the vector field.\n            kwargs: Additional arguments.\n        \"\"\"\n        self._create_indexes(index=index, indexes=indexes)\n\n    @override\n    async def _inner_upsert(self, records: Sequence[Any], **kwargs: Any) -> Sequence[TKey]:\n        \"\"\"Upsert records.\"\"\"\n        for vector_field in self.definition.vector_fields:\n            vectors_to_add = [record.get(vector_field.storage_name or vector_field.name) for record in records]\n            vectors = np.array(vectors_to_add, dtype=np.float32)\n            if not self.indexes[vector_field.name].is_trained:\n                raise VectorStoreOperationException(\n                    f\"This index (of type {type(self.indexes[vector_field.name])}) requires training, \"\n                    \"which is not supported. To train the index, \"\n                    f\"use <collection>.indexes[{vector_field.name}].train, \"\n                    \"see faiss docs for more details.\"\n                )\n            self.indexes[vector_field.name].add(vectors)  # type: ignore\n            start = len(self.indexes_key_map[vector_field.name])\n            for i, record in enumerate(records):\n                key = record[self.definition.key_field.name]\n                self.indexes_key_map[vector_field.name][key] = start + i\n        return await super()._inner_upsert(records, **kwargs)\n\n    @override\n    async def _inner_delete(self, keys: Sequence[TKey], **kwargs: Any) -> None:\n        for key in keys:\n            for vector_field in self.definition.vector_field_names:\n                if key in self.indexes_key_map[vector_field]:\n                    vector_index = self.indexes_key_map[vector_field][key]","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/connectors/faiss.py#L152-L188","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nimport faiss\nquantizer = faiss.IndexFlatL2(128)\nidx = faiss.IndexIVFFlat(quantizer, 128, 32)\ncollection.indexes['vec'] = idx   # not trained -> upsert raises [1300]\nawait collection.upsert(records)\n\n# after\ntraining = np.array(all_vectors, dtype=np.float32)\nidx.train(training)              # IVF/PQ indexes need this\nidx.add(training)                # optional: seed with training data\ncollection.indexes['vec'] = idx\nawait collection.upsert(records)","handlingStrategy":"validation","validationCode":"import numpy as np\n\ndef assert_indexes_trained(collection, n_training=None):\n    for vf in collection.definition.vector_fields:\n        idx = collection.indexes.get(vf.name)\n        if idx is None:\n            continue\n        if not idx.is_trained:\n            if n_training is None:\n                raise RuntimeError(f\"index '{vf.name}' is not trained; pass training vectors\")\n            training = np.asarray(training_vectors_for(vf), dtype=np.float32)\n            idx.train(training)\n    # now safe to upsert","typeGuard":"def is_index_ready(idx) -> bool:\n    # faiss indexes expose is_trained; flat indexes are always trained\n    return getattr(idx, 'is_trained', True)","tryCatchPattern":"from semantic_kernel.exceptions import VectorStoreOperationException\ntry:\n    await collection.upsert(records)\nexcept VectorStoreOperationException as ex:\n    if 'requires training' in str(ex):\n        collection.indexes[field_name].train(training_vectors)\n        await collection.upsert(records)\n    else:\n        raise","preventionTips":["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."],"tags":["faiss","vector-store","index-training","embeddings"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}