{"record":{"id":"e1b284313a6877db","repo":"langchain-ai/langchain","slug":"source-id-key-should-be-either-none-a-string-or-a","errorCode":null,"errorMessage":"source_id_key should be either None, a string or a callable. Got {source_id_key} of type {type(source_id_key)}.","messagePattern":"source_id_key should be either None, a string or a callable\\. Got (.+?) of type (.+?)\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/indexing/api.py","lineNumber":136,"sourceCode":"    if batch:\n        yield batch\n\n\ndef _get_source_id_assigner(\n    source_id_key: str | Callable[[Document], str] | None,\n) -> Callable[[Document], str | None]:\n    \"\"\"Get the source id from the document.\"\"\"\n    if source_id_key is None:\n        return lambda _doc: None\n    if isinstance(source_id_key, str):\n        return lambda doc: doc.metadata[source_id_key]\n    if callable(source_id_key):\n        return source_id_key\n    msg = (  # type: ignore[unreachable]\n        f\"source_id_key should be either None, a string or a callable. \"\n        f\"Got {source_id_key} of type {type(source_id_key)}.\"\n    )\n    raise ValueError(msg)\n\n\ndef _deduplicate_in_order(\n    hashed_documents: Iterable[Document],\n) -> Iterator[Document]:\n    \"\"\"Deduplicate a list of hashed documents while preserving order.\"\"\"\n    seen: set[str] = set()\n\n    for hashed_doc in hashed_documents:\n        if hashed_doc.id not in seen:\n            # At this stage, the id is guaranteed to be a string.\n            # Avoiding unnecessary run time checks.\n            seen.add(cast(\"str\", hashed_doc.id))\n            yield hashed_doc\n\n\nclass IndexingException(LangChainException):\n    \"\"\"Raised when an indexing operation fails.\"\"\"","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/indexing/api.py#L118-L154","documentation":"Raised by `_get_source_id_assigner` in `langchain_core.indexing.api`. During indexing with incremental/scoped_full cleanup, each Document must be traced back to an upstream source (e.g. a file path or URL) so stale copies can be deleted. The `source_id_key` parameter tells the indexer how to extract that ID and must be None, a metadata key name, or a callable — anything else is rejected.","triggerScenarios":"Passing `source_id_key=123`, a tuple, or a list to `index()`/`aindex()`; passing a dict-like object that is not a str; passing a non-callable object that was intended to be a function (e.g. referencing an attribute instead of the method).","commonSituations":"Config-driven pipelines where source_id_key comes from YAML/JSON and is parsed as a non-string type; typos like `source_id_key=doc.metadata[\"source\"]` (evaluates to a value, but if the metadata value is not a str — e.g. an int — this error fires at a different layer; here the error is on the key parameter itself).","solutions":["Use a metadata key string: `source_id_key=\"source\"` and ensure each document's metadata contains it.","Or use a callable: `source_id_key=lambda doc: doc.metadata[\"file_path\"]`.","Or pass None when using cleanup=None/'full', which does not need source IDs."],"exampleFix":"# before\nindex(vs, docs, rm, source_id_key=0, cleanup=\"incremental\")\n\n# after\nindex(vs, docs, rm, source_id_key=\"source\", cleanup=\"incremental\")","handlingStrategy":"type-guard","validationCode":"if source_id_key is not None and not isinstance(source_id_key, (str,)) and not callable(source_id_key):\n    raise TypeError(f\"bad source_id_key: {source_id_key!r}\")\nindex(vs, docs, rm, source_id_key=source_id_key, cleanup=\"incremental\")","typeGuard":"def is_valid_source_id_key(k) -> bool:\n    return k is None or isinstance(k, str) or callable(k)","tryCatchPattern":null,"preventionTips":["Parse config-driven source_id_key as a string and reject other types at load time.","Prefer callables for non-trivial extraction; they also give better error control."],"tags":["indexing","validation","cleanup"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}