{"record":{"id":"38bec5726609f0bc","repo":"microsoft/semantic-kernel","slug":"invalid-operator","errorCode":null,"errorMessage":"Invalid operator","messagePattern":"Invalid operator","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"python/samples/concepts/agents/autogen_conversable_agent/autogen_conversable_agent_convo_with_tools.py","lineNumber":39,"sourceCode":"This sample follows the AutoGen flow outlined here:\nhttps://microsoft.github.io/autogen/0.2/docs/tutorial/tool-use\n\"\"\"\n\n\nOperator = Literal[\"+\", \"-\", \"*\", \"/\"]\n\n\nasync def main():\n    def calculator(a: int, b: int, operator: Annotated[Operator, \"operator\"]) -> int:\n        if operator == \"+\":\n            return a + b\n        if operator == \"-\":\n            return a - b\n        if operator == \"*\":\n            return a * b\n        if operator == \"/\":\n            return int(a / b)\n        raise ValueError(\"Invalid operator\")\n\n    assistant = ConversableAgent(\n        name=\"Assistant\",\n        system_message=\"You are a helpful AI assistant. \"\n        \"You can help with simple calculations. \"\n        \"Return 'TERMINATE' when the task is done.\",\n        # Note: the model \"gpt-4o\" leads to a \"division by zero\" error that doesn't occur with \"gpt-4o-mini\"\n        # or even \"gpt-4\".\n        llm_config={\n            \"config_list\": [{\"model\": os.environ[\"OPENAI_CHAT_MODEL_ID\"], \"api_key\": os.environ[\"OPENAI_API_KEY\"]}]\n        },\n    )\n\n    # Create a thread for use with the agent.\n    thread: AutoGenConversableAgentThread = None\n\n    # Create a Semantic Kernel AutoGenConversableAgent based on the AutoGen ConversableAgent.\n    assistant_agent = AutoGenConversableAgent(conversable_agent=assistant)","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/samples/concepts/agents/autogen_conversable_agent/autogen_conversable_agent_convo_with_tools.py#L21-L57","documentation":"A sample-only ValueError raised by the local calculator() inner function when the 'operator' argument is not one of '+', '-', '*', '/'. It is demonstration logic inside an autogen sample, not part of the Semantic Kernel library surface. It exists to show how a tool function reports an invalid argument back to the agent.","triggerScenarios":"The LLM/agent or a direct caller invokes calculator(a, b, operator) with an operator value outside the four supported strings (e.g. '%', '^', 'plus', '', or a typo).","commonSituations":"The model passes a synonym ('plus'), a unicode operator, or an unsupported operator; or you reuse the sample's calculator verbatim and call it programmatically with a non-whitelisted value.","solutions":["Call calculator only with one of '+', '-', '*', '/'.","If you need more operators (%, **, //), extend the if-chain before the raise.","Normalize the operator before dispatch (e.g. map 'plus'->'+', '×'->'*').","Make the Operator type a Literal/Enum so callers see allowed values up front."],"exampleFix":"# before\nasync def main():\n    def calculator(a: int, b: int, operator: Annotated[Operator, \"operator\"]) -> int:\n        if operator == \"+\":\n            return a + b\n        # ...\n        raise ValueError(\"Invalid operator\")\n# after - typed operator + extra ops + normalization\nfrom typing import Literal\nOp = Literal[\"+\", \"-\", \"*\", \"/\", \"%\"]\ndef calculator(a: int, b: int, operator: Op) -> int:\n    mapping = {\"plus\": \"+\", \"minus\": \"-\", \"times\": \"*\", \"divide\": \"/\"}\n    operator = mapping.get(operator, operator)\n    ops = {\"+\": lambda: a + b, \"-\": lambda: a - b,\n           \"*\": lambda: a * b, \"/\": lambda: int(a / b),\n           \"%\": lambda: a % b}\n    if operator not in ops:\n        raise ValueError(f\"Invalid operator: {operator!r}\")\n    return ops[operator]()","handlingStrategy":"validation","validationCode":"ALLOWED = {\"+\", \"-\", \"*\", \"/\"}\ndef safe_calc(a, b, operator):\n    operator = {\"plus\": \"+\", \"minus\": \"-\", \"times\": \"*\", \"divide\": \"/\"}.get(operator, operator)\n    if operator not in ALLOWED:\n        raise ValueError(f\"Invalid operator: {operator!r}. Use one of {sorted(ALLOWED)}.\")\n    return {\"+\": a + b, \"-\": a - b, \"*\": a * b, \"/\": int(a / b)}[operator]","typeGuard":"from typing import Literal\nOp = Literal[\"+\", \"-\", \"*\", \"/\"]\ndef is_valid_operator(op: object) -> bool:\n    return op in (\"+\", \"-\", \"*\", \"/\")","tryCatchPattern":"try:\n    result = calculator(a, b, op)\nexcept ValueError as e:\n    # report back to the agent / caller with the allowed set\n    print(f\"{e}. Supported operators: + - * /\")","preventionTips":["Type the operator parameter as Literal['+','-','*','/'] so the model sees allowed values.","Describe allowed operators in the function docstring/annotation so the LLM does not invent synonyms.","Normalize synonyms before dispatch."],"tags":["python","sample","validation","agents"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}