{"record":{"id":"a09aef8f7b37a526","repo":"langchain-ai/langchain","slug":"ids-must-be-provided-for-deletion","errorCode":null,"errorMessage":"IDs must be provided for deletion","messagePattern":"IDs must be provided for deletion","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/indexing/in_memory.py","lineNumber":76,"sourceCode":"        return UpsertResponse(succeeded=ok_ids, failed=[])\n\n    @override\n    def delete(self, ids: list[str] | None = None, **kwargs: Any) -> DeleteResponse:\n        \"\"\"Delete by IDs.\n\n        Args:\n            ids: List of IDs to delete.\n\n        Raises:\n            ValueError: If IDs is None.\n\n        Returns:\n            A response object that contains the list of IDs that were successfully\n            deleted and the list of IDs that failed to be deleted.\n        \"\"\"\n        if ids is None:\n            msg = \"IDs must be provided for deletion\"\n            raise ValueError(msg)\n\n        ok_ids = []\n\n        for id_ in ids:\n            if id_ in self.store:\n                del self.store[id_]\n                ok_ids.append(id_)\n\n        return DeleteResponse(\n            succeeded=ok_ids, num_deleted=len(ok_ids), num_failed=0, failed=[]\n        )\n\n    @override\n    def get(self, ids: Sequence[str], /, **kwargs: Any) -> list[Document]:\n        return [self.store[id_] for id_ in ids if id_ in self.store]\n\n    @override\n    def _get_relevant_documents(","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/indexing/in_memory.py#L58-L94","documentation":"`ValueError` from the in-memory `DocumentIndex`/`RecordManager` family's `delete`: the `ids` argument is `None`. Deletion requires an explicit list of IDs (there is no 'delete all' via `None`), so the call is rejected rather than interpreted as a no-op or a wipe.","triggerScenarios":"Calling `store.delete(None)` or `await store.adelete(None)` on the in-memory index — commonly when upstream code computes IDs from an empty result and passes the resulting `None`, or when a caller tries `delete()` with no arguments on an API that declares `ids` optional but rejects `None`.","commonSituations":"`ids = search_results.get('ids')` returning `None` before `delete(ids)`; migrating code from a store where `delete(None)` meant 'delete all'; forgetting to handle an empty-match case in cleanup logic.","solutions":["Guard the call: only delete when you actually have IDs, e.g. `if ids: store.delete(ids)`.","To delete everything in the in-memory index, delete each known ID explicitly (`list(store.store.keys())`) or clear the container you built it over.","Trace where `None` originates (optional dict access, empty query results) and give it a default of `[]`."],"exampleFix":"# before\nids = response.get(\"ids\")  # may be None\nstore.delete(ids)\n\n# after\nids = response.get(\"ids\") or []\nif ids:\n    store.delete(ids)","handlingStrategy":"validation","validationCode":"ids = ids or []\nif ids:\n    store.delete(ids)","typeGuard":"def has_ids_to_delete(ids: list[str] | None) -> bool:\n    \"\"\"Type check plus emptiness guard for delete(ids).\"\"\"\n    return isinstance(ids, list) and len(ids) > 0 and all(isinstance(i, str) for i in ids)","tryCatchPattern":"try:\n    store.delete(ids)\nexcept ValueError as e:\n    if \"IDs must be provided\" in str(e):\n        pass  # nothing to delete; safe no-op\n    else:\n        raise","preventionTips":["Default optional id lists to [] instead of leaving them None","Handle empty search/query results before calling delete","Remember delete(None) is not 'delete all' — enumerate IDs explicitly"],"tags":["document-index","in-memory","validation"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}