{"record":{"id":"8e8ea9bb62a236c2","repo":"infiniflow/ragflow","slug":"invalid-logical-operator-should-be-and-or-or","errorCode":null,"errorMessage":"Invalid logical operator,should be 'and' or 'or'.","messagePattern":"Invalid logical operator,should be 'and' or 'or'\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/component/loopitem.py","lineNumber":146,"sourceCode":"        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\", \"\")\n            else:\n                raise ValueError(\"Invalid input mode.\")\n            conditions.append(self.evaluate_condition(var, operator, value))\n        should_end = all(conditions) if logical_operator == \"and\" else any(conditions) if logical_operator == \"or\" else None\n        if should_end is None:\n            raise ValueError(\"Invalid logical operator,should be 'and' or 'or'.\")\n\n        if should_end:\n            self._idx = -1\n            return True\n\n        return False\n\n    def next(self):\n        if self._idx == -1:\n            self._idx = 0\n        else:\n            self._idx += 1\n            if self._idx >= len(self._items):\n                self._idx = -1\n        return False\n\n    def thoughts(self) -> str:\n        return \"Next turn...\"","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/agent/component/loopitem.py#L128-L164","documentation":"ValueError from LoopItem.end(): after evaluating all termination conditions, the results are combined with all() when logical_operator=='and' or any() when 'or'; any other value (including empty/None or a typo like 'AND') makes should_end None and raises.","triggerScenarios":"The parent Loop's logical_operator attribute is missing, empty, or not exactly 'and'/'or' (e.g. 'AND', 'And', 'xor', ''). It is read from parent._param with no default normalization.","commonSituations":"Hand-edited canvas JSON where the key was deleted or capitalized; older templates saved before logical_operator existed; frontend writing a display label instead of the canonical token.","solutions":["Set the Loop component's logical operator to exactly 'and' or 'or' (lowercase) in the UI.","If editing JSON, add/fix \"logical_operator\": \"and\" on the Loop component's parameters.","Re-save the Loop component from the editor so the current schema writes the canonical value."],"exampleFix":"// before\n\"logical_operator\": \"AND\"\n\n// after\n\"logical_operator\": \"and\"","handlingStrategy":"validation","validationCode":"logical_operator = getattr(loop_param, 'logical_operator', 'and') or 'and'\nassert logical_operator in {'and', 'or'}, logical_operator","typeGuard":"def is_valid_logical_operator(op) -> bool:\n    return op in ('and', 'or')","tryCatchPattern":"try:\n    loop_item.end()\nexcept ValueError as e:\n    if 'Invalid logical operator' in str(e):\n        # set logical_operator to 'and'/'or' and re-run\n        ...","preventionTips":["Always set logical_operator to exactly 'and' or 'or'.","When generating canvas JSON, default the field rather than omitting it.","Re-save older Loop components after schema changes."],"tags":["loop","logical-operator","configuration","agent-canvas"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}