microsoft/semantic-kernel · error · NotImplementedError

Left side must be x.FIELD.

Error message

Left side must be x.FIELD.

What it means

SearchLambdaVisitor (used by Brave/Google search filter lambdas) only accepts comparisons of the exact shape `x.FIELD == VALUE`. The left operand must be an ast.Attribute access on an ast.Name (the lambda parameter). Anything else on the left raises NotImplementedError.

Solutions

  1. Rewrite the filter so the left side is the parameter attribute: `lambda x: x.field == VALUE`.
  2. Move any transformation into the constant value, not the field side.

Example fix

// before
lambda x: "news" == x.category   # value on the left
lambda x: str(x.year) == "2024"  # call on the left

// after
lambda x: x.category == "news"
lambda x: x.year == 2024
Defensive patterns

Strategy: validation

Validate before calling

import ast
node = ast.parse(filter_src, mode='eval').body  # the lambda
def check_left(n):
    if isinstance(n, ast.Compare):
        assert isinstance(n.left, ast.Attribute) and isinstance(n.left.value, ast.Name), 'left must be x.FIELD'
    if isinstance(n, ast.BoolOp):
        for v in n.values: check_left(v)
check_left(node.body)

Type guard

def is_x_field_compare(node: ast.Compare) -> bool:
    return isinstance(node.left, ast.Attribute) and isinstance(node.left.value, ast.Name)

Prevention

When it happens

Trigger: Supplying a filter lambda whose left side is not `x.FIELD`: a reversed comparison (`lambda x: VALUE == x.field`), a call expression (`func(x.field) == ...`), a subscript, or a bare comparison without an attribute.

Common situations: Writing the value first; wrapping the field in a function; using a comparison the visitor does not model.

Related errors


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

Appendix: source

Thrown at python/semantic_kernel/connectors/_search_shared.py:30


class SearchLambdaVisitor(ast.NodeVisitor):
    """Visitor to parse a lambda function for Brave and Google Search filters."""

    def __init__(self, valid_parameters: list[str]):
        """Initialize the visitor with a list of valid parameters."""
        self.filters: list[dict[str, str]] = []
        self.valid_parameters = valid_parameters

    @override
    def visit_Lambda(self, node):
        self.visit(node.body)

    @override
    def visit_Compare(self, node):
        # Only support x.FIELD == VALUE
        if not (isinstance(node.left, ast.Attribute) and isinstance(node.left.value, ast.Name)):
            raise NotImplementedError("Left side must be x.FIELD.")
        field = node.left.attr
        if not (len(node.ops) == 1 and isinstance(node.ops[0], ast.Eq)):
            raise NotImplementedError("Only == comparisons are supported.")
        right = node.comparators[0]
        if isinstance(right, ast.Constant):
            if right.value is None:
                raise NotImplementedError("None values are not supported.")
            value = str(right.value)
        else:
            raise NotImplementedError("Only constant values are supported on the right side.")
        if field not in self.valid_parameters:
            raise ValueError(f"Field '{field}' is not supported.")
        self.filters.append({field: quote_plus(value)})

    @override
    def visit_BoolOp(self, node):
        if not isinstance(node.op, ast.And):
            raise NotImplementedError("Only 'and' of == comparisons is supported.")

View on GitHub (pinned to c028a0c7dc)