{"id":"17633e51e4e82e97","repo":"psycopg/psycopg2","slug":"bound-flags-not-valid-bounds-r","errorCode":null,"errorMessage":"bound flags not valid: {bounds!r}","messagePattern":"bound flags not valid: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/_range.py","lineNumber":50,"sourceCode":"from psycopg2.extensions import new_type, new_array_type, register_type\n\n\nclass Range:\n    \"\"\"Python representation for a PostgreSQL |range|_ type.\n\n    :param lower: lower bound for the range. `!None` means unbound\n    :param upper: upper bound for the range. `!None` means unbound\n    :param bounds: one of the literal strings ``()``, ``[)``, ``(]``, ``[]``,\n        representing whether the lower or upper bounds are included\n    :param empty: if `!True`, the range is empty\n\n    \"\"\"\n    __slots__ = ('_lower', '_upper', '_bounds')\n\n    def __init__(self, lower=None, upper=None, bounds='[)', empty=False):\n        if not empty:\n            if bounds not in ('[)', '(]', '()', '[]'):\n                raise ValueError(f\"bound flags not valid: {bounds!r}\")\n\n            self._lower = lower\n            self._upper = upper\n            self._bounds = bounds\n        else:\n            self._lower = self._upper = self._bounds = None\n\n    def __repr__(self):\n        if self._bounds is None:\n            return f\"{self.__class__.__name__}(empty=True)\"\n        else:\n            return \"{}({!r}, {!r}, {!r})\".format(self.__class__.__name__,\n                self._lower, self._upper, self._bounds)\n\n    def __str__(self):\n        if self._bounds is None:\n            return 'empty'\n","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/psycopg/psycopg2/blob/3a6d9d6ddc6b53eaa80b712f5fa6b23abbdc38db/lib/_range.py#L32-L68","documentation":"Raised by Range.__init__ when the 'bounds' argument is not one of the four valid PostgreSQL range bound flags: '[)', '(]', '()', or '[]'. These flags denote whether each endpoint is inclusive (bracket) or exclusive (parenthesis). Any other string value (including lowercase variants or reversed pairs) is rejected because it cannot be mapped to a PostgreSQL range literal.","triggerScenarios":"Constructing a Range (or any subclass like NumericRange, DateRange) with an explicit bounds keyword that is misspelled or wrong, e.g. Range(1, 10, bounds='[]'), Range(1, 10, bounds='[ ]'), Range(1, 10, bounds=')('), or passing a non-string object. The check at lib/_range.py:49 runs only when empty=False (the default).","commonSituations":"Developers confuse the bracket/parenthesis order (writing '][' or ')('), add a space inside the flag, or use uppercase. Also occurs when bounds are read from user input or a config file without validation. The empty=True path bypasses this entirely, so some users forget that non-empty ranges always require a valid flag.","solutions":["Use exactly one of '[)', '(]', '()', '[]' as the bounds argument (default is '[)').","If the bounds string comes from external input, validate it against ('[)', '(]', '()', '[]') before constructing the Range.","If you actually want an empty range, pass empty=True instead of trying to express emptiness via bounds."],"exampleFix":"// before\nr = Range(1, 10, bounds=']( ')\n// after\nr = Range(1, 10, bounds='[)')","handlingStrategy":"validation","validationCode":"VALID_BOUNDS = ('[)', '(]', '()', '[]')\nif bounds not in VALID_BOUNDS:\n    raise ValueError(f'invalid bounds {bounds!r}; expected one of {VALID_BOUNDS}')\nr = Range(lower, upper, bounds=bounds)","typeGuard":"def is_valid_bounds(b) -> bool:\n    return isinstance(b, str) and b in ('[)', '(]', '()', '[]')","tryCatchPattern":"try:\n    r = Range(lo, hi, bounds=b)\nexcept ValueError as e:\n    # log and fall back to default bounds\n    r = Range(lo, hi)","preventionTips":["Never construct bounds strings dynamically without validating against the 4 allowed flags.","Treat bounds as an enum, not free text; centralize the allowed set in a constant."],"tags":["validation","range","constructor","value-error"],"analyzedSha":"3a6d9d6ddc6b53eaa80b712f5fa6b23abbdc38db","analyzedAt":"2026-08-04T19:56:51.958Z","schemaVersion":2}