microsoft/semantic-kernel · error · VectorStoreOperationException

Attribute '{node.func.attr}' is not callable in filter expre

Error message

Attribute '{node.func.attr}' is not callable in filter expressions.

What it means

Thrown by the runtime safe filter evaluator (_eval_Call, in_memory.py:301-304) when a method-call expression such as `x.foo()` resolves via getattr to an existing attribute that is not callable. The parse-time allowlist can only check node and function names; whether the resolved value is actually callable is only known at evaluation time, so this is a value-level guard.

Source

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

                ) from e
            return func(*args)

        if isinstance(node.func, ast.Attribute):
            target = self.evaluate(node.func.value, context)
            if node.func.attr == "contains":
                if len(args) != 1:
                    raise VectorStoreOperationException("Method 'contains' expects exactly one argument.")
                return args[0] in target

            try:
                func = getattr(target, node.func.attr)
            except AttributeError as e:
                raise VectorStoreOperationException(
                    f"Method '{node.func.attr}' is not available in filter expressions."
                ) from e

            if not callable(func):
                raise VectorStoreOperationException(
                    f"Attribute '{node.func.attr}' is not callable in filter expressions."
                )
            return func(*args)

        raise VectorStoreOperationException(
            f"Call target node type '{type(node.func).__name__}' is not allowed in filter expressions."
        )

    def _compare(self, operator_node: ast.AST, left: Any, right: Any) -> bool:
        """Evaluate a comparison operator."""
        if isinstance(operator_node, ast.Eq):
            return left == right
        if isinstance(operator_node, ast.NotEq):
            return left != right
        if isinstance(operator_node, ast.Lt):
            return left < right
        if isinstance(operator_node, ast.LtE):
            return left <= right

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Rename the data field so it does not collide with an allowlisted method name.
  2. Use subscript access for data, e.g. `x['items']` instead of calling `x.items()`, when you mean field value not a method.
  3. Restructure the filter so you only call methods on values you know are the right type (strings for .lower()/.strip(), mappings for .keys()/.values()/.items()).
  4. Wrap the search in try/except VectorStoreOperationException if the collision is unavoidable and degrade gracefully.

Example fix

# before
VectorSearchOptions(filter="lambda x: x.items() == [1,2]")  # field 'items' holds a list
# after
VectorSearchOptions(filter="lambda x: x['items'] == [1,2]")  # subscript data access
Defensive patterns

Strategy: try-catch

Try / catch

try:
    results = await collection.search(search_type=SearchType.VECTOR, options=opts)
except VectorStoreOperationException as e:
    logger.warning("filter rejected: %s", e.__cause__ or e)
    results = None

Prevention

When it happens

Trigger: A string lambda filter where a data field name collides with an allowlisted method name (lower, upper, strip, startswith, endswith, contains, get, keys, values, items) but the stored value is a non-callable scalar/sequence. Example: a record has a field `items=[1,2,3]` and the filter is `lambda x: x.items()`.

Common situations: Naming a data model field the same as an allowed method; calling .get()/.keys()/.items()/.lower() on a field whose runtime value is a number or string; copy-pasting dict-style calls onto record fields that hold scalars.

Related errors


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