langchain-ai/langchain · error · TypeError
Vectorstore should be either a VectorStore or a DocumentInde
Error message
Vectorstore should be either a VectorStore or a DocumentIndex. Got {type(destination)}. What it means
Raised in `index()` when the destination object is neither a `VectorStore` nor a `DocumentIndex`. The indexer must upsert and delete documents through one of those two protocols; passing a retriever, a bare client, a string DSN, or a duck-typed object that never subclasses the right base class results in a `TypeError`. The type annotation makes this unreachable for typed callers, but dynamic code bypasses it.
Source
Thrown at libs/core/langchain_core/indexing/api.py:450
if not hasattr(destination, method):
msg = (
f"Vectorstore {destination} does not have required method {method}"
)
raise ValueError(msg)
if type(destination).delete == VectorStore.delete:
# Checking if the VectorStore has overridden the default delete method
# implementation which just raises a NotImplementedError
msg = "Vectorstore has not implemented the delete method"
raise ValueError(msg)
elif isinstance(destination, DocumentIndex):
pass
else:
msg = ( # type: ignore[unreachable]
f"Vectorstore should be either a VectorStore or a DocumentIndex. "
f"Got {type(destination)}."
)
raise TypeError(msg)
if isinstance(docs_source, BaseLoader):
try:
doc_iterator = docs_source.lazy_load()
except NotImplementedError:
doc_iterator = iter(docs_source.load())
else:
doc_iterator = iter(docs_source)
source_id_assigner = _get_source_id_assigner(source_id_key)
# Mark when the update started.
index_start_dt = record_manager.get_time()
num_added = 0
num_skipped = 0
num_updated = 0
num_deleted = 0
scoped_full_cleanup_source_ids: set[str] = set()View on GitHub (pinned to e32fa9a52e)
Solutions
- Pass the LangChain `VectorStore` wrapper object itself (e.g. the `Chroma` instance, not its `_collection`).
- Make custom destinations subclass `VectorStore` or implement `DocumentIndex`.
- If given a retriever, recover the store via its `vectorstore` attribute where available.
Example fix
# before index(chroma._collection, docs, rm, cleanup="full") # after index(chroma, docs, rm, cleanup="full")
Defensive patterns
Strategy: type-guard
Validate before calling
from langchain_core.vectorstores import VectorStore
assert isinstance(destination, VectorStore), (
f"expected VectorStore, got {type(destination).__name__}; "
"pass the LangChain wrapper, not a retriever or raw client"
)
index(destination, docs, rm, cleanup="full") Type guard
def is_indexing_destination(obj) -> bool:
from langchain_core.vectorstores import VectorStore
from langchain_core.indexing.api import DocumentIndex
return isinstance(obj, (VectorStore, DocumentIndex)) Prevention
- Never unwrap stores (`._collection`, `.client`) before calling index().
- Annotate parameters as VectorStore and run mypy to catch duck-typed misuse.
When it happens
Trigger: Calling `index(my_retriever, docs, rm)`; passing `vectorstore.as_retriever()` output; passing the underlying client (e.g. a `chromadb.Collection`) instead of the LangChain wrapper; test mocks without proper subclassing.
Common situations: Confusing retrievers with stores; grabbing low-level SDK clients from LangChain integrations (`store._collection`); refactors that swap the store for a facade object.
Related errors
- Vectorstore should be either a VectorStore or a DocumentInde
- The delete operation to VectorStore failed.
- The delete operation to DocumentIndex failed.
- Vectorstore {destination} does not have required method {met
- Vectorstore has not implemented the delete method
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/03aeacf9d7eeef82.
Report an issue: GitHub.