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

  1. Use exactly one of: "incremental", "full", "scoped_full", or None.
  2. Validate the config value against the allowed set at load time and fail fast with a clear message.
  3. 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

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


AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14). Data as JSON: /api/errors/306af3badd57d5c8. Report an issue: GitHub.