{"record":{"id":"fa083f6626b4a10e","repo":"infiniflow/ragflow","slug":"loop-condition-is-incomplete","errorCode":null,"errorMessage":"Loop condition is incomplete.","messagePattern":"Loop condition is incomplete\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/component/loopitem.py","lineNumber":132,"sourceCode":"                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\", \"\")\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","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/agent/component/loopitem.py#L114-L150","documentation":"ValueError from LoopItem.end() while evaluating the parent Loop's termination conditions. Each item in loop_termination_condition must contain both a truthy 'variable' and a truthy 'operator'; an item missing either makes the condition incomplete and the loop cannot decide whether to stop.","triggerScenarios":"A termination-condition row saved with an empty variable selector or an empty operator; a condition added in the UI but never configured; canvas JSON hand-edited to remove a key.","commonSituations":"Users add a termination condition then forget to set the variable; duplicated loops where one row lost its binding; templates with placeholder condition rows.","solutions":["Complete the condition: choose a variable and an operator for every row in the Loop's termination-condition list.","Delete unused/placeholder condition rows entirely.","Validate loop_termination_condition entries all have 'variable' and 'operator' before running the canvas."],"exampleFix":"// before\n\"loop_termination_condition\": [{\"variable\": \"\", \"operator\": \"=\"}]\n\n// after\n\"loop_termination_condition\": [{\"variable\": \"loop_x@counter\", \"operator\": \"=\", \"value\": 10}]","handlingStrategy":"validation","validationCode":"for item in loop_param.loop_termination_condition:\n    assert item.get('variable') and item.get('operator'), f'incomplete condition row: {item}'","typeGuard":"def condition_complete(item: dict) -> bool:\n    return bool(item.get('variable')) and bool(item.get('operator'))","tryCatchPattern":"try:\n    loop_item.end()\nexcept ValueError as e:\n    if 'incomplete' in str(e):\n        # complete or delete the condition row\n        ...","preventionTips":["Fully configure each termination condition (variable + operator) or delete it.","Never leave placeholder rows in loop termination conditions.","Validate conditions at canvas-save time in custom tooling."],"tags":["loop","validation","configuration","agent-canvas"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}