{"record":{"id":"5d0c43229da3ad8d","repo":"OpenBMB/ChatDev","slug":"max-iterations-must-be-1","errorCode":null,"errorMessage":"max_iterations must be >= 1","messagePattern":"max_iterations must be >= 1","errorType":"validation","errorClass":"ConfigError","httpStatus":null,"severity":"error","filePath":"entity/configs/node/loop_counter.py","lineNumber":37,"sourceCode":"\n    max_iterations: int = 10\n    reset_on_emit: bool = True\n    message: Optional[str] = None\n\n    @classmethod\n    def from_dict(cls, data: Mapping[str, Any] | None, *, path: str) -> \"LoopCounterConfig\":\n        mapping = require_mapping(data or {}, path)\n        max_iterations_raw = mapping.get(\"max_iterations\", 10)\n        try:\n            max_iterations = int(max_iterations_raw)\n        except (TypeError, ValueError) as exc:  # pragma: no cover - defensive\n            raise ConfigError(\n                \"max_iterations must be an integer\",\n                extend_path(path, \"max_iterations\"),\n            ) from exc\n\n        if max_iterations < 1:\n            raise ConfigError(\"max_iterations must be >= 1\", extend_path(path, \"max_iterations\"))\n\n        reset_on_emit = bool(mapping.get(\"reset_on_emit\", True))\n        message = optional_str(mapping, \"message\", path)\n\n        return cls(\n            max_iterations=max_iterations,\n            reset_on_emit=reset_on_emit,\n            message=message,\n            path=path,\n        )\n\n    def validate(self) -> None:\n        if self.max_iterations < 1:\n            raise ConfigError(\"max_iterations must be >= 1\", extend_path(self.path, \"max_iterations\"))\n\n    FIELD_SPECS = {\n        \"max_iterations\": ConfigFieldSpec(\n            name=\"max_iterations\",","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/OpenBMB/ChatDev/blob/4fb2db0ea90375ce1059f44fe03ffbd191a7a169/entity/configs/node/loop_counter.py#L19-L55","documentation":"LoopCounterConfig.from_dict rejects a max_iterations value that coerces to an integer below 1. A loop counter that never iterates is meaningless, so zero and negatives are config errors.","triggerScenarios":"Passing max_iterations: 0, a negative number, or a numeric string like '0'/'-3' that int() happily converts before the range check.","commonSituations":"Disabling a loop by setting iterations to 0 (use node removal or a bypass instead); arithmetic that computes a zero/negative bound.","solutions":["Set max_iterations to at least 1","To 'disable' the loop, remove the counter from the graph or gate execution elsewhere","Compute bounds with max(1, computed_value) when derived from variables"],"exampleFix":"# before\n{\"max_iterations\": 0}\n# after\n{\"max_iterations\": 1}","handlingStrategy":"validation","validationCode":"n = int(data.get('max_iterations', 10))\nif n < 1:\n    data['max_iterations'] = 1","typeGuard":"def iterations_in_range(data: dict) -> bool:\n    try:\n        return int(data.get('max_iterations', 10)) >= 1\n    except (TypeError, ValueError):\n        return False","tryCatchPattern":"try:\n    LoopCounterConfig.from_dict(data, path='lc')\nexcept ConfigError as e:\n    if '>= 1' in str(e):\n        data['max_iterations'] = 1\n        LoopCounterConfig.from_dict(data, path='lc')\n    else:\n        raise","preventionTips":["Clamp computed caps with max(1, n)","Don't use 0 to disable loops — remove the node","Assert bounds in builder code"],"tags":["config","loop","range","validation","python"],"backgroundTag":"value-out-of-range","analyzedSha":"4fb2db0ea90375ce1059f44fe03ffbd191a7a169","analyzedAt":"2026-08-27T14:35:29.622Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}