{"record":{"id":"66587542dc6b4893","repo":"langchain-ai/deepagents","slug":"rubric-max-iterations-must-be-none-or-a-positive-i","errorCode":null,"errorMessage":"rubric_max_iterations must be None or a positive integer","messagePattern":"rubric_max_iterations must be None or a positive integer","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/_server_config.py","lineNumber":500,"sourceCode":"            msg = \"shell_allow_list must be None or non-empty\"\n            raise ValueError(msg)\n        # `allow_fs_tools` is a security control: `None` means unrestricted, but\n        # an explicit list must be a usable allowlist. Own the non-empty +\n        # `read_file`-required invariant here (the single authoritative point\n        # for both the env round-trip via `from_env` and direct construction)\n        # rather than deferring to `FilesystemMiddleware`, which would only\n        # surface the violation a process boundary away. `_parse_allow_fs_tools_flag`\n        # still enforces the same rule at the CLI for a friendlier error.\n        if self.allow_fs_tools is not None:\n            if len(self.allow_fs_tools) == 0:\n                msg = \"allow_fs_tools must be None or a non-empty list\"\n                raise ValueError(msg)\n            if \"read_file\" not in self.allow_fs_tools:\n                msg = \"allow_fs_tools must include 'read_file'\"\n                raise ValueError(msg)\n        if isinstance(self.rubric_max_iterations, bool):\n            msg = \"rubric_max_iterations must be None or a positive integer\"\n            raise TypeError(msg)\n        if self.rubric_max_iterations is not None and self.rubric_max_iterations <= 0:\n            msg = \"rubric_max_iterations must be None or a positive integer\"\n            raise ValueError(msg)\n        if isinstance(self.cli_max_retries, bool):\n            msg = \"cli_max_retries must be None or a non-negative integer\"\n            raise TypeError(msg)\n        if self.cli_max_retries is not None and self.cli_max_retries < 0:\n            msg = \"cli_max_retries must be None or a non-negative integer\"\n            raise ValueError(msg)\n        if isinstance(self.recursion_limit, bool):\n            msg = \"recursion_limit must be None or a positive integer\"\n            raise TypeError(msg)\n        if self.recursion_limit is not None and self.recursion_limit <= 0:\n            msg = \"recursion_limit must be None or a positive integer\"\n            raise ValueError(msg)\n\n    # ------------------------------------------------------------------\n    # Serialization","sourceCodeStart":482,"sourceCodeEnd":518,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/_server_config.py#L482-L518","documentation":"ServerConfig validates rubric_max_iterations: booleans are rejected with a TypeError (bool is a subclass of int in Python and would silently pass numeric checks) and non-positive integers are rejected with this ValueError. The field must be None (unlimited/default behavior) or an integer >= 1. This error fires when a non-None, <= 0 integer is supplied.","triggerScenarios":"Constructing ServerConfig with rubric_max_iterations=0 or any negative integer (e.g. -1). Note rubric_max_iterations=True raises a TypeError instead, and the same message is also raised at line 503 (error 47) from the companion <= 0 check.","commonSituations":"Reading the limit from env/config and parsing an unset value as 0; a loop-computation that produced -1 as a sentinel; copying a 0-based config convention from another setting that uses 0 to mean 'off'.","solutions":["Set rubric_max_iterations to a positive integer (>= 1), e.g. 5","Set rubric_max_iterations=None to use the library default instead of 0","Fix the upstream source (env var parse, computed value) so 'disabled' is represented as None, not 0"],"exampleFix":"// before\nconfig = ServerConfig(rubric_max_iterations=int(os.environ.get('RUBRIC_ITERS', 0)))\n// after\nraw = os.environ.get('RUBRIC_ITERS')\nconfig = ServerConfig(rubric_max_iterations=int(raw) if raw else None)","handlingStrategy":"validation","validationCode":"def validate_rubric_max_iterations(v):\n    if isinstance(v, bool):\n        raise TypeError(\"rubric_max_iterations must be None or a positive integer\")\n    if v is not None and v <= 0:\n        raise ValueError(\"rubric_max_iterations must be None or a positive integer\")","typeGuard":"def is_valid_rubric_max_iterations(v) -> bool:\n    return v is None or (isinstance(v, int) and not isinstance(v, bool) and v > 0)","tryCatchPattern":"try:\n    config = ServerConfig(rubric_max_iterations=value)\nexcept (TypeError, ValueError) as e:\n    if \"rubric_max_iterations\" in str(e):\n        config = ServerConfig(rubric_max_iterations=None)  # fall back to default\n    else:\n        raise","preventionTips":["Represent 'not configured' as None, never 0 or -1","Remember bool is an int in Python — exclude it before numeric validation","Validate env/config values at parse time with an explicit positive-int check"],"tags":["config-validation","valueerror","integer-range"],"backgroundTag":"invalid-config-value","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}