{"record":{"id":"83124968eccadca8","repo":"crewAIInc/crewAI","slug":"no-documents-were-inserted","errorCode":null,"errorMessage":"No documents were inserted.","messagePattern":"No documents were inserted\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"lib/crewai-tools/src/crewai_tools/tools/mongodb_vector_search_tool/vector_search.py","lineNumber":265,"sourceCode":"        if not texts:\n            return []\n        # Compute embedding vectors\n        embeddings = self._embed_texts(texts)\n        docs = [\n            {\n                \"_id\": ObjectId(i),\n                self.text_key: t,\n                self.embedding_key: embedding,\n                **m,\n            }\n            for i, t, m, embedding in zip(\n                ids, texts, metadatas, embeddings, strict=False\n            )\n        ]\n        operations = [ReplaceOne({\"_id\": doc[\"_id\"]}, doc, upsert=True) for doc in docs]\n        result = self._coll.bulk_write(operations)\n        if result.upserted_ids is None:\n            raise ValueError(\"No documents were inserted.\")\n        return [str(_id) for _id in result.upserted_ids.values()]\n\n    def _run(self, query: str) -> str:\n        from bson import json_util\n\n        try:\n            query_config = self.query_config or MongoDBVectorSearchConfig()\n            limit = query_config.limit\n            oversampling_factor = query_config.oversampling_factor\n            pre_filter = query_config.pre_filter\n            include_embeddings = query_config.include_embeddings\n            post_filter_pipeline = query_config.post_filter_pipeline\n\n            query_vector = self._embed_texts([query])[0]\n\n            # Atlas Vector Search, potentially with filter\n            stage = {\n                \"index\": self.vector_index_name,","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai-tools/src/crewai_tools/tools/mongodb_vector_search_tool/vector_search.py#L247-L283","documentation":"upsert() writes documents with bulk_replace_one(..., upsert=True) and then checks result.upserted_ids. If upserted_ids is None/empty, it raises ValueError('No documents were inserted.') — meaning Mongo acknowledged the bulk_write but reported no upserts. In practice this happens when every operation matched an existing _id (updates, not inserts), or when the input arrays were empty so no operations were built.","triggerScenarios":"Calling upsert with ids that already exist in the collection (ReplaceOne with upsert=True updates in place — no upserted ids); passing empty ids/texts lists; strict=False zip silently truncating mismatched-length inputs to nothing; duplicate ids in one batch.","commonSituations":"Re-ingesting the same corpus expecting new inserts; empty first batch from a chunker bug; ids list length != texts length so zip yields fewer/zero pairs.","solutions":["If re-ingesting existing ids, treat this as expected: catch the ValueError or check matched_count instead of upserted_ids semantics","Validate inputs are non-empty and equal-length before calling: assert len(ids) == len(texts) and ids","For genuinely new data, confirm you are not reusing ObjectIds from a previous run — generate fresh ones or drop the collection first"],"exampleFix":"# before\nreturned = tool.upsert(texts=docs, ids=existing_ids)  # ValueError on re-run\n\n# after\n# treat existing ids as update, not error\nids = [str(ObjectId()) for _ in docs]  # or verify len(inputs) > 0 first\nassert docs, \"nothing to upsert\"\nreturned = tool.upsert(texts=docs, ids=ids)","handlingStrategy":"validation","validationCode":"def upsert_inputs_valid(texts, ids, metadatas=None) -> bool:\n    return bool(texts) and bool(ids) and len(texts) == len(ids) and (\n        metadatas is None or len(metadatas) == len(texts)\n    )","typeGuard":null,"tryCatchPattern":"try:\n    tool.upsert(texts=texts, ids=ids)\nexcept ValueError as e:\n    if \"No documents were inserted\" in str(e):\n        # ids already existed — treat as idempotent update, not a failure\n        pass\n    else:\n        raise","preventionTips":["Validate non-empty, equal-length inputs before upsert","Understand upsert semantics: existing _id means update, not insert","Generate fresh ObjectIds for new documents instead of reusing old ones"],"tags":["mongodb","upsert","validation","data-ingestion"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}