{"record":{"id":"64f46c84bb76128a","repo":"pandas-dev/pandas","slug":"value-must-be-a-positive-integer-or-none","errorCode":null,"errorMessage":"Value must be a positive integer or None","messagePattern":"Value must be a positive integer or None","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/config_init.py","lineNumber":478,"sourceCode":"\nmax_threads_doc = \"\"\"\n: int or None\n    Maximum number of worker threads for parallel operations (e.g. ``read_csv``\n    for large files).  ``None`` (the default) means use ``min(os.cpu_count(), 4)``,\n    further limited to the CPUs available to the process (CPU affinity and cgroup\n    limits); on Windows the default is ``1``, as parallel reading is not faster\n    there.  Set to ``1`` to disable parallel execution, or to a fixed number to\n    raise the cap or to limit thread usage when pandas is embedded in a larger\n    parallel workflow.  Ignored on Emscripten/Pyodide, which cannot spawn threads.\n\"\"\"\n\n\ndef _is_positive_int_or_none(value: Any) -> None:\n    if value is None:\n        return\n    if isinstance(value, int) and value >= 1:\n        return\n    raise ValueError(\"Value must be a positive integer or None\")\n\n\nwith cf.config_prefix(\"mode\"):\n    cf.register_option(\n        \"max_threads\",\n        None,\n        max_threads_doc,\n        validator=_is_positive_int_or_none,\n    )\n\n\nstring_storage_doc = \"\"\"\n: string\n    The default storage for StringDtype.\n\"\"\"\n\n\ndef is_valid_string_storage(value: Any) -> None:","sourceCodeStart":460,"sourceCodeEnd":496,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/config_init.py#L460-L496","documentation":"ValueError raised by _is_positive_int_or_none() in pandas/core/config_init.py:478, the validator registered for the 'mode.max_threads' option. The option caps worker threads for parallel operations such as read_csv on large files; legal values are None (auto) or a positive int (>=1). Passing 0, a negative number, a float, a bool-as-int surprise, or a string raises this error at option-set time.","triggerScenarios":"pd.set_option('mode.max_threads', 0); pd.set_option('mode.max_threads', -1); pd.set_option('mode.max_threads', 4.0) (float not int); pd.set_option('mode.max_threads', '4') (string); pd.option_context('mode.max_threads', value) with a value read from an environment variable/config file without coercion; math.floor()/division producing a float that is then passed in.","commonSituations":"Reading thread counts from env vars or YAML config and passing the raw string; computing CPU counts with operations that yield floats; disabling parallelism by passing 0 instead of 1 or None; CI configs that set the option to a placeholder like '' or 'auto'; version upgrades where the option was renamed or its validation tightened.","solutions":["Pass None to disable the cap (auto) or 1 to force single-threaded execution.","Coerce config-sourced values explicitly: int(value) and validate value >= 1 before calling set_option, falling back to None on parse failure.","When reading from os.environ, wrap in try/except and default to None: n = int(os.environ['PD_MAX_THREADS']) if set and int-parseable and >=1 else None.","Avoid bools: remember True == 1 passes isinstance int but conveys the wrong intent; pass an explicit int."],"exampleFix":"// before\npd.set_option('mode.max_threads', threads_from_config)  # '0' or 4.0 -> ValueError\n\n// after\nraw = threads_from_config\nn = None if raw in (None, '', 'auto') else int(raw)\nif n is not None and n < 1:\n    raise ValueError(f'invalid thread count {raw!r}')\npd.set_option('mode.max_threads', n)","handlingStrategy":"validation","validationCode":"from typing import Any\n\ndef coerce_max_threads(value: Any):\n    \"\"\"Return a value safe for pd.set_option('mode.max_threads', ...) or raise.\"\"\"\n    if value is None or value in ('', 'auto', 'none'):\n        return None\n    if isinstance(value, bool) or not isinstance(value, int):\n        if isinstance(value, str):\n            value = int(value.strip())\n        elif isinstance(value, float) and value.is_integer():\n            value = int(value)\n        else:\n            raise ValueError(f'invalid max_threads: {value!r}')\n    if value < 1:\n        raise ValueError(f'max_threads must be >= 1 or None, got {value}')\n    return value\n\nimport pandas as pd\npd.set_option('mode.max_threads', coerce_max_threads(config_value))","typeGuard":"def is_positive_int_or_none(value) -> bool:\n    return value is None or (isinstance(value, int) and not isinstance(value, bool) and value >= 1)","tryCatchPattern":"import pandas as pd\n\ntry:\n    pd.set_option('mode.max_threads', raw)\nexcept ValueError as e:\n    if 'positive integer or None' in str(e):\n        # fall back to auto\n        pd.set_option('mode.max_threads', None)\n    else:\n        raise","preventionTips":["Always coerce env/config strings to int and bounds-check >= 1 before set_option.","Use None for 'auto' and 1 for 'single-threaded'; never 0 or negative.","Reject bools explicitly (isinstance(x, bool)) since True/False are ints in Python.","Centralize option setting in a helper so the coercion lives in one place."],"tags":["config","options","threading","validation","read-csv"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}