langchain-ai/langchain · error · ValueError
cleanup should be one of 'incremental', 'full', 'scoped_full
Error message
cleanup should be one of 'incremental', 'full', 'scoped_full' or None. Got {cleanup}. What it means
Raised in `index()` (langchain_core.indexing.api) when the `cleanup` argument is not one of the supported modes. Cleanup controls how stale documents are removed: 'incremental' and 'scoped_full' need per-source tracking, 'full' compares the entire index, and None disables cleanup. An unrecognized string (or wrong type) is rejected before any indexing work starts.
Source
Thrown at libs/core/langchain_core/indexing/api.py:416
ValueError: If cleanup mode is incremental and source_id_key is None.
ValueError: If `VectorStore` does not have
"delete" and "add_documents" required methods.
ValueError: If source_id_key is not None, but is not a string or callable.
TypeError: If `vectorstore` is not a `VectorStore` or a DocumentIndex.
AssertionError: If `source_id` is None when cleanup mode is incremental.
(should be unreachable code).
"""
# Behavior is deprecated, but we keep it for backwards compatibility.
# # Warn only once per process.
if key_encoder == "sha1":
_warn_about_sha1()
if cleanup not in {"incremental", "full", "scoped_full", None}:
msg = (
f"cleanup should be one of 'incremental', 'full', 'scoped_full' or None. "
f"Got {cleanup}."
)
raise ValueError(msg)
if (cleanup in {"incremental", "scoped_full"}) and source_id_key is None:
msg = (
"Source id key is required when cleanup mode is incremental or scoped_full."
)
raise ValueError(msg)
destination = vector_store # Renaming internally for clarity
# If it's a vectorstore, let's check if it has the required methods.
if isinstance(destination, VectorStore):
# Check that the Vectorstore has required methods implemented
methods = ["delete", "add_documents"]
for method in methods:
if not hasattr(destination, method):
msg = (
f"Vectorstore {destination} does not have required method {method}"View on GitHub (pinned to e32fa9a52e)
Solutions
- Use exactly one of: "incremental", "full", "scoped_full", or None.
- Validate the config value against the allowed set at load time and fail fast with a clear message.
- Remember "full" is expensive for large stores — prefer "incremental" with a source_id_key when possible.
Example fix
# before index(vs, docs, rm, cleanup="upsert") # after index(vs, docs, rm, cleanup="incremental", source_id_key="source")
Defensive patterns
Strategy: validation
Validate before calling
VALID = {"incremental", "full", "scoped_full", None}
cleanup = cleanup if cleanup in VALID else None
index(vs, docs, rm, cleanup=cleanup, **( {"source_id_key": "source"} if cleanup else {} )) Type guard
def is_valid_cleanup(mode) -> bool:
return mode in {"incremental", "full", "scoped_full", None} Prevention
- Type cleanup as Literal['incremental','full','scoped_full'] | None in your config schema.
- Normalize case and strip whitespace on config-sourced cleanup values.
When it happens
Trigger: Calling `index(vs, docs, rm, cleanup="upsert")`, `cleanup="Incremental"` (wrong case), `cleanup="all"`, or passing a non-string like 1/True.
Common situations: Config-driven pipelines with free-text cleanup settings; copy from tutorials using older/imagined mode names; case-sensitivity mistakes from env vars.
Related errors
- source_id_key should be either None, a string or a callable.
- Batch size must be a positive integer, got {size}.
- Unsupported hashing algorithm: {algorithm}
- The delete operation to VectorStore failed.
- The delete operation to DocumentIndex failed.
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/306af3badd57d5c8.
Report an issue: GitHub.