{"record":{"id":"d64524dae4933ff2","repo":"MemPalace/mempalace","slug":"update-requires-at-least-one-of-documents-metadat-d64524","errorCode":null,"errorMessage":"update requires at least one of documents, metadatas, embeddings","messagePattern":"update requires at least one of documents, metadatas, embeddings","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"mempalace/backends/qdrant.py","lineNumber":861,"sourceCode":"        for doc_id, doc, meta, vector in zip(ids, documents, metadatas, vectors):\n            points.append(\n                {\n                    \"id\": _point_id(doc_id),\n                    \"vector\": vector,\n                    \"payload\": {\n                        _PAYLOAD_ID: str(doc_id),\n                        _PAYLOAD_DOCUMENT: str(doc),\n                        _PAYLOAD_METADATA: _jsonable_metadata(meta),\n                        \"updated_at\": _utcnow(),\n                    },\n                }\n            )\n        self._client.upsert_points(self._remote_collection, points)\n        self._backend._write_marker(self._palace, self._config)\n\n    def update(self, *, ids, documents=None, metadatas=None, embeddings=None):\n        if documents is None and metadatas is None and embeddings is None:\n            raise ValueError(\"update requires at least one of documents, metadatas, embeddings\")\n        n = len(ids)\n        for label, value in (\n            (\"documents\", documents),\n            (\"metadatas\", metadatas),\n            (\"embeddings\", embeddings),\n        ):\n            if value is not None and len(value) != n:\n                raise ValueError(f\"{label} length {len(value)} does not match ids length {n}\")\n        existing = self.get(ids=ids, include=[\"documents\", \"metadatas\", \"embeddings\"])\n        by_id = {\n            rid: (existing.documents[i], existing.metadatas[i], existing.embeddings[i])\n            for i, rid in enumerate(existing.ids)\n            if existing.embeddings is not None\n        }\n        out_ids = []\n        out_docs = []\n        out_metas = []\n        out_embeddings = []","sourceCodeStart":843,"sourceCodeEnd":879,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/backends/qdrant.py#L843-L879","documentation":"Raised by QdrantCollection.update() when documents, metadatas and embeddings are all None. update() performs a read-merge-write; with nothing to merge it would be a no-op that still round-trips to the server, so the API requires at least one field to change.","triggerScenarios":"Calling update(ids=my_ids) with no other kwargs — often from generic code that builds kwargs dynamically and ends up with all-None values (e.g. an update dict where every optional field was absent).","commonSituations":"A generic CRUD layer forwarding user input where all optional fields were omitted; a partial-update helper that receives an empty patch dict; conditional code paths that compute new values but a branch leaves everything None.","solutions":["Guard before calling: if documents is metadatas is embeddings is None: return (nothing to update)","If the intent was deletion, call delete() instead","If the intent was a no-op touch of updated_at, do it explicitly with metadatas (merge same metadata)","Audit the caller building the kwargs dict — usually an empty patch should be short-circuited earlier"],"exampleFix":"# before\n updates = {k: v for k, v in patch.items() if k in (\"documents\",\"metadatas\",\"embeddings\")}\n collection.update(ids=ids, **updates)  # empty patch -> ValueError\n// after\n if not any(updates.get(k) is not None for k in (\"documents\",\"metadatas\",\"embeddings\")):\n     return  # nothing to update\n collection.update(ids=ids, **updates)","handlingStrategy":"validation","validationCode":"if documents is None and metadatas is None and embeddings is None:\n    return  # nothing to update","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Short-circuit empty patches in your update layer before touching the backend","Build update kwargs explicitly rather than forwarding possibly-empty dicts"],"tags":["api-misuse","validation","qdrant"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}