{"record":{"id":"7469ae4f4062a57c","repo":"infiniflow/ragflow","slug":"invalid-operator-operator","errorCode":null,"errorMessage":"Invalid operator: {operator}","messagePattern":"Invalid operator: (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"agent/component/loopitem.py","lineNumber":122,"sourceCode":"                return value in var\n            elif operator == \"not contains\":\n                return value not in var\n\n            elif operator == \"is\":\n                return var == value\n            elif operator == \"is not\":\n                return var != value\n\n            elif operator == \"empty\":\n                return len(var) == 0\n            elif operator == \"not empty\":\n                return len(var) > 0\n        elif var is None:\n            if operator == \"empty\":\n                return True\n            return False\n\n        raise Exception(f\"Invalid operator: {operator}\")\n\n    def end(self):\n        if self._idx == -1:\n            return True\n        parent = self.get_parent()\n        logical_operator = parent._param.logical_operator if hasattr(parent._param, \"logical_operator\") else \"and\"\n        conditions = []\n        for item in parent._param.loop_termination_condition:\n            if not item.get(\"variable\") or not item.get(\"operator\"):\n                raise ValueError(\"Loop condition is incomplete.\")\n            var = self._canvas.get_variable_value(item[\"variable\"])\n            operator = item[\"operator\"]\n            input_mode = item.get(\"input_mode\", \"constant\")\n\n            if input_mode == \"variable\":\n                value = self._canvas.get_variable_value(item.get(\"value\", \"\"))\n            elif input_mode == \"constant\":\n                value = item.get(\"value\", \"\")","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/agent/component/loopitem.py#L104-L140","documentation":"Generic Exception from LoopItem.evaluate_condition: after walking all supported operator branches (comparisons, contains, is/is not, empty/not empty, with None handling), an unrecognized operator string falls through to this raise. It signals canvas data containing an operator outside the evaluated set.","triggerScenarios":"A loop_termination_condition entry whose 'operator' field is a typo or unsupported value (e.g. '>=' instead of '≥', 'includes', empty string combined with a non-None var). The check at loopitem.py:132 only requires operator to be truthy, not valid, so bad values reach evaluate_condition.","commonSituations":"Hand-editing canvas JSON and entering a JS-style operator; version drift where a template was authored against a different operator vocabulary; frontend saved a localized operator label.","solutions":["Open the loop termination condition and pick the operator from the dropdown instead of typing it.","If editing JSON directly, use exactly the operators the component implements (e.g. '=', '≠', '>', '<', '≥', '≤', 'contains', 'empty').","Re-create the condition row from scratch rather than patching the operator string."],"exampleFix":"// before\n{\"variable\": \"x\", \"operator\": \">=\", \"value\": 5}\n\n// after\n{\"variable\": \"x\", \"operator\": \"≥\", \"value\": 5}","handlingStrategy":"validation","validationCode":"VALID_OPS = {'=', '≠', '>', '<', '≥', '≤', 'contains', 'not contains', 'is', 'is not', 'empty', 'not empty'}\nfor item in parent._param.loop_termination_condition:\n    assert item['operator'] in VALID_OPS, item['operator']","typeGuard":"def is_valid_loop_operator(op: str) -> bool:\n    return op in {'=', '≠', '>', '<', '≥', '≤', 'contains', 'not contains', 'is', 'is not', 'empty', 'not empty'}","tryCatchPattern":"try:\n    loop_item.end()\nexcept Exception as e:\n    if 'Invalid operator' in str(e):\n        # pick operator from UI dropdown and re-save\n        ...","preventionTips":["Select operators from the UI dropdown; never free-type them.","Use Unicode ≥/≤ (not >=/<=) in loop conditions.","Lint canvas JSON against the component's operator vocabulary before deployment."],"tags":["loop","operator","configuration","agent-canvas"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}