microsoft/semantic-kernel · error · VectorStoreOperationException

Dictionary unpacking is not allowed in filter expressions.

Error message

Dictionary unpacking is not allowed in filter expressions.

What it means

_eval_Dict iterates key/value pairs; a dict-unpacking entry (the {**other} form) has a None key in the AST, which the evaluator rejects because unpacking can pull arbitrary, unvalidated objects into the filter. Raises VectorStoreOperationException.

Source

Thrown at python/semantic_kernel/connectors/in_memory.py:209

        return [self.evaluate(element, context) for element in node.elts]

    def _eval_Tuple(self, node: ast.Tuple, context: Mapping[str, Any]) -> tuple[Any, ...]:
        """Evaluate a tuple literal."""
        self._ensure_literal_collection_size(len(node.elts))
        return tuple(self.evaluate(element, context) for element in node.elts)

    def _eval_Set(self, node: ast.Set, context: Mapping[str, Any]) -> set[Any]:
        """Evaluate a set literal."""
        self._ensure_literal_collection_size(len(node.elts))
        return {self.evaluate(element, context) for element in node.elts}

    def _eval_Dict(self, node: ast.Dict, context: Mapping[str, Any]) -> dict[Any, Any]:
        """Evaluate a dict literal."""
        self._ensure_literal_collection_size(len(node.keys))
        result: dict[Any, Any] = {}
        for key, value in zip(node.keys, node.values, strict=True):
            if key is None:
                raise VectorStoreOperationException("Dictionary unpacking is not allowed in filter expressions.")
            result[self.evaluate(key, context)] = self.evaluate(value, context)
        return result

    def _eval_BoolOp(self, node: ast.BoolOp, context: Mapping[str, Any]) -> Any:
        """Evaluate boolean operators with Python short-circuit semantics."""
        if isinstance(node.op, ast.And):
            result = self.evaluate(node.values[0], context)
            for value in node.values[1:]:
                if not result:
                    return result
                result = self.evaluate(value, context)
            return result
        if isinstance(node.op, ast.Or):
            result = self.evaluate(node.values[0], context)
            for value in node.values[1:]:
                if result:
                    return result
                result = self.evaluate(value, context)

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Do not use ** unpacking inside filter expressions; use explicit key/value literals only.
  2. Restructure the filter to avoid constructing dicts, or precompute the dict outside the filter.

Example fix

# before
VectorSearchOptions(filter=lambda x: {'k': 1, **x.extra}['k'] == 1)  # -> [1313]

# after
VectorSearchOptions(filter=lambda x: x.get('k') == 1)
Defensive patterns

Strategy: validation

Validate before calling

import ast

def has_no_dict_unpacking(filter_str: str) -> None:
    for node in ast.walk(ast.parse(filter_str, mode='eval')):
        if isinstance(node, ast.Dict) and any(k is None for k in node.keys):
            raise ValueError('dict unpacking (**...) is not allowed in filters')

Try / catch

from semantic_kernel.exceptions import VectorStoreOperationException
try:
    await collection.search(vector=[...], options=opts)
except VectorStoreOperationException as ex:
    if 'Dictionary unpacking' in str(ex):
        # rewrite the filter without {**...}
        ...
    raise

Prevention

When it happens

Trigger: A string filter containing a dict literal with unpacking, e.g. lambda x: {'a': 1, **x.meta}[...]. Note this only reaches the evaluator if dict literals are allowed and the static checks did not reject it.

Common situations: Attempting to build complex dicts inside a filter; copying Python dict idioms into filter expressions; adversarial filter input.

Related errors


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/bffc27b1d50066bb. Report an issue: GitHub.