MemPalace/mempalace · error · ValueError

delete requires either ids= or where=

Error message

delete requires either ids= or where=

What it means

Raised by MilvusCollection.delete() (mempalace/backends/milvus.py:798) when the method is called with neither ids= nor where=. delete() is keyword-only and needs at least one selector so it knows which rows to remove; an argumentless delete would otherwise wipe the collection, so the backend refuses instead of guessing.

Source

Thrown at mempalace/backends/milvus.py:798

            )
        return GetResult(
            ids=[str(row.get(FIELD_ID, "")) for row in rows],
            documents=[row.get(FIELD_DOCUMENT, "") for row in rows] if spec.documents else [],
            metadatas=[self._extract_metadata(row) for row in rows] if spec.metadatas else [],
            embeddings=[row.get(FIELD_VECTOR) or [] for row in rows] if spec.embeddings else None,
        )

    def get_all_metadata(self, where: Optional[dict] = None) -> list[dict]:
        rows = self._collect_by_filter(
            filter_expr=translate_where(where),
            output_fields=[FIELD_ID, FIELD_METADATA],
        )
        return [self._extract_metadata(row) for row in rows]

    def delete(self, *, ids=None, where=None):
        filter_expr = translate_where(where)
        if ids is None and where is None:
            raise ValueError("delete requires either ids= or where=")
        if not self._remote_exists():
            if self._marker_exists():
                raise CollectionNotInitializedError(self._collection_name)
            return
        if ids is not None and where is not None:
            rows = self._collect_by_filter(
                filter_expr=filter_expr,
                output_fields=[FIELD_ID],
            )
            allowed = {row[FIELD_ID] for row in rows}
            ids = [doc_id for doc_id in ids if doc_id in allowed]
        if ids is not None:
            if not ids:
                return
            self._client.delete(collection_name=self._remote_collection, ids=list(ids))
        else:
            self._client.delete(collection_name=self._remote_collection, filter=filter_expr)

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Pass an explicit selector: collection.delete(ids=[...]) or collection.delete(where={...})
  2. If you build filters dynamically, guard before calling: if ids or where: collection.delete(ids=ids, where=where)
  3. To delete everything in the collection, use backend.delete_collection() / recreate instead of an argumentless delete
  4. Remember both parameters are keyword-only: delete(ids=...) not delete([...])

Example fix

// before
collection.delete()

# after
collection.delete(ids=['drawer-42'])
# or
collection.delete(where={'wing': 'projects'})
Defensive patterns

Strategy: validation

Validate before calling

def safe_delete(collection, ids=None, where=None):
    if ids is None and where is None:
        raise ValueError('refusing to delete without ids or where')
    collection.delete(ids=ids, where=where)

Type guard

def is_delete_selector(ids, where) -> bool:
    return ids is not None or where is not None

Try / catch

try:
    collection.delete(ids=ids, where=where)
except ValueError as e:
    if 'requires either' in str(e):
        # build a real selector and retry, never delete blindly
        raise

Prevention

When it happens

Trigger: Calling collection.delete() with no arguments, or passing ids/where positionally (they are keyword-only: 'def delete(self, *, ids=None, where=None)'). Also calling delete(ids=[]) is fine, but delete(where={}) with an empty dict: 'where is None' is False so it passes, whereas delete() with both omitted triggers it.

Common situations: Copy-paste from a Chroma-like API where delete is also keyword-only but the caller forgot the filter; refactoring that builds a where clause conditionally and ends up passing None for both; interactive experimentation.

Related errors


AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15). Data as JSON: /api/errors/64d0e296701d446b. Report an issue: GitHub.