microsoft/semantic-kernel · error · NotImplementedError
Unsupported operator: {type(op)}
Error message
Unsupported operator: {type(op)} What it means
The connector translates Python filter lambdas into Cosmos SQL by walking the AST. Inside a comparison node it only maps a fixed set of operators (In, NotIn, Eq, NotEq, Gt, GtE, Lt, LtE). Any comparison operator not in that set reaches the trailing raise NotImplementedError. This means the filter expression used a Python comparison that the translator was never taught to render as SQL.
Source
Thrown at python/semantic_kernel/connectors/azure_cosmos_db.py:931
match op:
case ast.In():
# Cosmos DB: ARRAY_CONTAINS(right, left)
return f"ARRAY_CONTAINS({right}, {left})"
case ast.NotIn():
return f"NOT ARRAY_CONTAINS({right}, {left})"
case ast.Eq():
return f"{left} = {right}"
case ast.NotEq():
return f"{left} != {right}"
case ast.Gt():
return f"{left} > {right}"
case ast.GtE():
return f"{left} >= {right}"
case ast.Lt():
return f"{left} < {right}"
case ast.LtE():
return f"{left} <= {right}"
raise NotImplementedError(f"Unsupported operator: {type(op)}")
case ast.BoolOp():
op_str = "AND" if isinstance(node.op, ast.And) else "OR"
return "(" + f" {op_str} ".join([parse(v) for v in node.values]) + ")"
case ast.UnaryOp():
match node.op:
case ast.Not():
return f"NOT ({parse(node.operand)})"
case ast.UAdd():
return f"+{parse(node.operand)}"
case ast.USub():
return f"-{parse(node.operand)}"
case ast.Invert():
raise NotImplementedError("Invert operation is not supported.")
raise NotImplementedError(f"Unsupported unary operator: {type(node.op)}")
case ast.Attribute():
# Cosmos DB: c.field_name
if node.attr not in self.definition.storage_names:
raise VectorStoreOperationException(View on GitHub (pinned to c028a0c7dc)
Solutions
- Replace 'is'/'is not' comparisons with '=='/'!=' in the filter lambda so they compile to ast.Eq / ast.NotEq, which the translator supports.
- Restrict filters to the supported operator set (==, !=, <, >, <=, >=, in, not in) and the supported logical/unary ops.
- For null checks use == None / != None rather than is None / is not None.
Example fix
// before options = VectorSearchOptions(filter=lambda x: x.category is None) // after options = VectorSearchOptions(filter=lambda x: x.category == None)
Defensive patterns
Strategy: validation
Validate before calling
import ast
SUPPORTED_OPS = (ast.Eq, ast.NotEq, ast.Gt, ast.GtE, ast.Lt, ast.LtE, ast.In, ast.NotIn)
tree = ast.parse(filter_src, mode="eval")
for node in ast.walk(tree):
if isinstance(node, ast.Compare):
for op in node.ops:
if not isinstance(op, SUPPORTED_OPS):
raise ValueError(f"Filter uses unsupported operator: {type(op).__name__}") Type guard
def is_supported_filter_op(node: ast.Compare) -> bool:
ok = (ast.Eq, ast.NotEq, ast.Gt, ast.GtE, ast.Lt, ast.LtE, ast.In, ast.NotIn)
return all(isinstance(op, ok) for op in node.ops) Prevention
- Use == / != instead of is / is not in filter lambdas.
- Stick to the documented comparison operator subset when authoring filters.
- Lint filter lambdas against the supported AST operator set before runtime.
When it happens
Trigger: Writing a filter lambda using an unsupported comparison operator, most commonly identity checks (a is b / a is not b, i.e. ast.Is / ast.IsNot) which Python emits for the 'is' keyword. The AST visitor's Compare branch has no case for them.
Common situations: A developer writes lambda x: x.category is None or x.tag is sentinel in a VectorSearchOptions.filter, expecting equality semantics; 'is' compiles to ast.Is, which is unsupported, whereas == compiles to ast.Eq and would work.
Related errors
- Invert operation is not supported.
- Constants or variables are not supported, use a value or att
- Unsupported constant type: {type(node.value)}
- Field '{node.attr}' not in data model (storage property name
- Unsupported operator: {type(op)}
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/9bbe18da7e48b1e9.
Report an issue: GitHub.