psycopg/psycopg2 · error · NotImplementedError
RangeAdapter must be subclassed overriding its name or the g
Error message
RangeAdapter must be subclassed overriding its name or the getquoted() method
What it means
Raised by RangeAdapter.getquoted() when the adapter's 'name' class attribute is still None. RangeAdapter is an abstract base: concrete subclasses must either set a 'name' (the PostgreSQL range type name) or override getquoted() to produce the serialized representation. Instantiating the bare RangeAdapter and letting it adapt a Range will trigger this because name is None by default.
Source
Thrown at lib/_range.py:257
This is an abstract class: concrete classes must set a `name` class
attribute or override `getquoted()`.
"""
name = None
def __init__(self, adapted):
self.adapted = adapted
def __conform__(self, proto):
if self._proto is ISQLQuote:
return self
def prepare(self, conn):
self._conn = conn
def getquoted(self):
if self.name is None:
raise NotImplementedError(
'RangeAdapter must be subclassed overriding its name '
'or the getquoted() method')
r = self.adapted
if r.isempty:
return b"'empty'::" + self.name.encode('utf8')
if r.lower is not None:
a = adapt(r.lower)
if hasattr(a, 'prepare'):
a.prepare(self._conn)
lower = a.getquoted()
else:
lower = b'NULL'
if r.upper is not None:
a = adapt(r.upper)
if hasattr(a, 'prepare'):View on GitHub (pinned to 3a6d9d6ddc)
Solutions
- Subclass RangeAdapter and set a 'name' class attribute to the PostgreSQL range type, e.g. class MyAdapter(RangeAdapter): name = 'myrange'.
- Alternatively, override getquoted() in the subclass to return the proper bytes.
- Prefer using register_range() or the built-in casters (NumericRange, DateRange, etc.) which wire up adapters automatically.
Example fix
// before
class MyAdapter(RangeAdapter): pass
register_adapter(MyRange, MyAdapter)
// after
class MyAdapter(RangeAdapter):
name = 'myrange'
register_adapter(MyRange, MyAdapter) Defensive patterns
Strategy: type-guard
Validate before calling
if getattr(MyAdapter, 'name', None) is None and 'getquoted' not in MyAdapter.__dict__:
raise TypeError('Adapter must set name or override getquoted') Type guard
def is_concrete_range_adapter(cls) -> bool:
return (isinstance(cls, type)
and issubclass(cls, RangeAdapter)
and cls is not RangeAdapter
and (getattr(cls, 'name', None) is not None
or 'getquoted' in cls.__dict__)) Try / catch
try:
adapter.getquoted()
except NotImplementedError:
# adapter not concrete; use a built-in caster instead Prevention
- Prefer register_range() over manually wiring adapters.
- Treat RangeAdapter as abstract; always subclass and set 'name'.
When it happens
Trigger: Directly creating RangeAdapter(some_range) without subclassing, or defining a subclass that forgets to set 'name' and does not override getquoted(). This happens during adaptation (when psycopg2 adapts a Range subclass for SQL) via the register_adapter mechanism at lib/_range.py:470.
Common situations: A developer creates a custom Range subclass and registers RangeAdapter (the base) instead of a concrete subclass. Also happens when experimenting with the adapter API without reading the docstring that marks RangeAdapter as abstract (lib/_range.py:237-242).
Related errors
- pgrange must be a string or a RangeAdapter strict subclass
- DictCursorBase can't be instantiated without a row factory.
- bound flags not valid: {bounds!r}
- pyrange must be a type or a Range strict subclass
- range types not available in version %s
AI-assisted analysis of psycopg/psycopg2@3a6d9d6ddc (2026-08-04).
Data as JSON: /data/errors/d572e85e483b6256.json.
Report an issue: GitHub.