{"id":"284596fa980ca8cf","repo":"psycopg/psycopg2","slug":"pyrange-must-be-a-type-or-a-range-strict-subclass","errorCode":null,"errorMessage":"pyrange must be a type or a Range strict subclass","messagePattern":"pyrange must be a type or a Range strict subclass","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/_range.py","lineNumber":338,"sourceCode":"                    self.adapter = pgrange\n            except TypeError:\n                pass\n\n        if self.adapter is None:\n            raise TypeError(\n                'pgrange must be a string or a RangeAdapter strict subclass')\n\n        self.range = None\n        try:\n            if isinstance(pyrange, str):\n                self.range = type(pyrange, (Range,), {})\n            if issubclass(pyrange, Range) and pyrange is not Range:\n                self.range = pyrange\n        except TypeError:\n            pass\n\n        if self.range is None:\n            raise TypeError(\n                'pyrange must be a type or a Range strict subclass')\n\n    @classmethod\n    def _from_db(self, name, pyrange, conn_or_curs):\n        \"\"\"Return a `RangeCaster` instance for the type *pgrange*.\n\n        Raise `ProgrammingError` if the type is not found.\n        \"\"\"\n        from psycopg2.extensions import STATUS_IN_TRANSACTION\n        from psycopg2.extras import _solve_conn_curs\n        conn, curs = _solve_conn_curs(conn_or_curs)\n\n        if conn.info.server_version < 90200:\n            raise ProgrammingError(\"range types not available in version %s\"\n                % conn.info.server_version)\n\n        # Store the transaction status of the connection to revert it after use\n        conn_status = conn.status","sourceCodeStart":320,"sourceCodeEnd":356,"githubUrl":"https://github.com/psycopg/psycopg2/blob/3a6d9d6ddc6b53eaa80b712f5fa6b23abbdc38db/lib/_range.py#L320-L356","documentation":"Raised by RangeCaster._create_ranges() (lib/_range.py:337-339) when the 'pyrange' argument is neither a string, nor a type, nor a strict subclass of Range (Range itself is excluded). The pyrange defines the Python class that PostgreSQL range values are cast into, so it must be a concrete Range subclass or a name from which one is generated.","triggerScenarios":"Constructing RangeCaster with a pyrange that is a non-type value (e.g. an instance, a number), the bare Range base class, or a class unrelated to Range. Examples: RangeCaster('myrange', range, ...), RangeCaster('myrange', 42, ...), RangeCaster('myrange', some_instance, ...).","commonSituations":"Developers confuse Python's builtin 'range' type with psycopg2's Range, passing the builtin. Or they pass an instance instead of a class. The exclusion of the base Range (line 332) also trips people who pass 'Range' expecting generic behavior.","solutions":["Pass a strict subclass of Range (e.g. NumericRange, DateRange, or your own subclass) as pyrange.","Or pass a string to have RangeCaster auto-generate a new Range subclass with that name.","Double-check you are not passing Python's builtin range type."],"exampleFix":"// before\ncaster = RangeCaster('myrange', range, oid=123, subtype_oid=23)\n// after\nclass MyRange(Range): pass\ncaster = RangeCaster('myrange', MyRange, oid=123, subtype_oid=23)","handlingStrategy":"type-guard","validationCode":"import builtins\nif pyrange is Range or pyrange is builtins.range:\n    raise TypeError('pyrange must be a strict Range subclass, not base Range or builtin range')\nif not (isinstance(pyrange, (str, type)) and (isinstance(pyrange, str) or issubclass(pyrange, Range))):\n    raise TypeError('pyrange must be a string or Range subclass')","typeGuard":"def is_valid_pyrange(p) -> bool:\n    import builtins\n    return (isinstance(p, str)\n            or (isinstance(p, type) and issubclass(p, Range) and p is not Range\n                and p is not builtins.range))","tryCatchPattern":"try:\n    caster = RangeCaster('myrange', pyrange, ...)\nexcept TypeError:\n    caster = RangeCaster('myrange', 'AutoRange', ...)","preventionTips":["Do not confuse psycopg2.Range with Python's builtin range.","Define an explicit subclass rather than reusing the base Range."],"tags":["type-error","range","rangecaster","constructor","type-confusion"],"analyzedSha":"3a6d9d6ddc6b53eaa80b712f5fa6b23abbdc38db","analyzedAt":"2026-08-04T19:56:51.958Z","schemaVersion":2}