microsoft/semantic-kernel · error · VectorStoreOperationException

AST node type '{type(node).__name__}' is not supported durin

Error message

AST node type '{type(node).__name__}' is not supported during filter evaluation.

What it means

_SafeFilterEvaluator.evaluate dispatches on the AST node class name via getattr(self, '_eval_' + type(node).__name__). If no such handler method exists it raises VectorStoreOperationException. This is the runtime-evaluation counterpart to the static allowed_filter_ast_nodes check; normally the static check rejects unknown node types first, so this fires when the static allowlist was widened by a subclass without adding a matching _eval_* method (an evaluator/validator inconsistency).

Source

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

    def __init__(
        self,
        *,
        direct_call_functions: dict[str, Callable[..., Any]],
        blocked_attributes: set[str],
        max_literal_collection_size: int,
        max_sequence_repeat_size: int,
    ):
        self._direct_call_functions = direct_call_functions
        self._blocked_attributes = blocked_attributes
        self._max_literal_collection_size = max_literal_collection_size
        self._max_sequence_repeat_size = max_sequence_repeat_size

    def evaluate(self, node: ast.AST, context: Mapping[str, Any]) -> Any:
        """Evaluate a supported AST node."""
        evaluator = getattr(self, f"_eval_{type(node).__name__}", None)
        if evaluator is None:
            raise VectorStoreOperationException(
                f"AST node type '{type(node).__name__}' is not supported during filter evaluation."
            )
        return evaluator(node, context)

    def _eval_Constant(self, node: ast.Constant, context: Mapping[str, Any]) -> Any:
        """Evaluate a constant literal."""
        del context
        if isinstance(node.value, str) and len(node.value) > self._max_literal_collection_size:
            raise VectorStoreOperationException(
                "String literals in filter expressions exceed the maximum allowed size."
            )
        return node.value

    def _eval_Name(self, node: ast.Name, context: Mapping[str, Any]) -> Any:
        """Evaluate a variable reference."""
        if node.id not in context:
            raise VectorStoreOperationException(f"Use of name '{node.id}' is not allowed in filter expressions.")
        return context[node.id]

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Subclass _SafeFilterEvaluator and add an _eval_<NodeName> method for every node type you added to allowed_filter_ast_nodes.
  2. Remove the unsupported node from allowed_filter_ast_nodes so the static check rejects it clearly.
  3. Stick to the built-in supported nodes (Compare, BoolOp, UnaryOp, BinOp, Call, Name, Attribute, Subscript, Constant, list/tuple/set/dict literals).

Example fix

# before
class MyCollection(InMemoryCollection):
    allowed_filter_ast_nodes = InMemoryCollection.allowed_filter_ast_nodes | {ast.IfExp}
# evaluating 'lambda x: x.a if x.b else x.c' -> [1307]

# after
class MyEvaluator(_SafeFilterEvaluator):
    def _eval_IfExp(self, node, context):
        return self.evaluate(node.body, context) if self.evaluate(node.test, context) else self.evaluate(node.orelse, context)
Defensive patterns

Strategy: validation

Validate before calling

import ast

def supported_node_names(evaluator) -> set[str]:
    return {n[len('_eval_'):] for n in dir(evaluator) if n.startswith('_eval_')}

def filter_uses_only_evaluatable(filter_str: str, evaluator) -> None:
    ok = supported_node_names(evaluator)
    for node in ast.walk(ast.parse(filter_str, mode='eval')):
        if type(node).__name__ not in ok and type(node).__name__ not in {
            'Expression', 'Lambda', 'arguments', 'arg', 'Load',
            'And', 'Or', 'Not', 'Eq', 'NotEq', 'Lt', 'LtE', 'Gt', 'GtE',
            'In', 'NotIn', 'Is', 'IsNot', 'Add', 'Sub', 'Mult', 'Div', 'Mod', 'FloorDiv',
        }:
            raise ValueError(f"filter uses unsupported node {type(node).__name__}")

Type guard

def evaluator_handles(evaluator, node: ast.AST) -> bool:
    return callable(getattr(evaluator, f'_eval_{type(node).__name__}', None))

Try / catch

from semantic_kernel.exceptions import VectorStoreOperationException
try:
    await collection.search(vector=[...], options=VectorSearchOptions(filter=f))
except VectorStoreOperationException as ex:
    if 'is not supported during filter evaluation' in str(ex):
        # rewrite the filter using only built-in supported nodes
        ...
    raise

Prevention

When it happens

Trigger: A subclass adds a node type to allowed_filter_ast_nodes (e.g. ast.IfExp, ast.DictComp, ast.GeneratorExp, ast.Starred, ast.JoinedStr) but does not implement the corresponding _eval_<NodeName> on the evaluator, then a string filter using that construct is evaluated against records.

Common situations: Customizing the filter sandbox to support ternaries or comprehensions; upgrading the library so a previously-added custom node no longer has an evaluator; subclassing InMemoryCollection to relax limits.

Related errors


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