crewAIInc/crewAI · warning · ValueError
No documents were inserted.
Error message
No documents were inserted.
What it means
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.
Source
Thrown at lib/crewai-tools/src/crewai_tools/tools/mongodb_vector_search_tool/vector_search.py:265
if not texts:
return []
# Compute embedding vectors
embeddings = self._embed_texts(texts)
docs = [
{
"_id": ObjectId(i),
self.text_key: t,
self.embedding_key: embedding,
**m,
}
for i, t, m, embedding in zip(
ids, texts, metadatas, embeddings, strict=False
)
]
operations = [ReplaceOne({"_id": doc["_id"]}, doc, upsert=True) for doc in docs]
result = self._coll.bulk_write(operations)
if result.upserted_ids is None:
raise ValueError("No documents were inserted.")
return [str(_id) for _id in result.upserted_ids.values()]
def _run(self, query: str) -> str:
from bson import json_util
try:
query_config = self.query_config or MongoDBVectorSearchConfig()
limit = query_config.limit
oversampling_factor = query_config.oversampling_factor
pre_filter = query_config.pre_filter
include_embeddings = query_config.include_embeddings
post_filter_pipeline = query_config.post_filter_pipeline
query_vector = self._embed_texts([query])[0]
# Atlas Vector Search, potentially with filter
stage = {
"index": self.vector_index_name,View on GitHub (pinned to 754d7323be)
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
Example fix
# before returned = tool.upsert(texts=docs, ids=existing_ids) # ValueError on re-run # after # treat existing ids as update, not error ids = [str(ObjectId()) for _ in docs] # or verify len(inputs) > 0 first assert docs, "nothing to upsert" returned = tool.upsert(texts=docs, ids=ids)
Defensive patterns
Strategy: validation
Validate before calling
def upsert_inputs_valid(texts, ids, metadatas=None) -> bool:
return bool(texts) and bool(ids) and len(texts) == len(ids) and (
metadatas is None or len(metadatas) == len(texts)
) Try / catch
try:
tool.upsert(texts=texts, ids=ids)
except ValueError as e:
if "No documents were inserted" in str(e):
# ids already existed — treat as idempotent update, not a failure
pass
else:
raise Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Project name '{name}' would generate folder name '{folder_na
- Project name '{name}' contains no valid characters for a Pyt
- Project name '{name}' would generate class name '{class_name
- Project name '{name}' would generate class name '{class_name
- Project name cannot be empty
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/83124968eccadca8.
Report an issue: GitHub.