psycopg/psycopg2 · error · NotImplementedError
DictCursorBase can't be instantiated without a row factory.
Error message
DictCursorBase can't be instantiated without a row factory.
What it means
Raised by DictCursorBase.__init__ (lib/extras.py:72-74) when a cursor is instantiated without a 'row_factory' keyword. DictCursorBase is an abstract base for DictCursor/RealDictCursor; concrete subclasses must supply a row_factory (a callable that builds each row). Instantiating the base class directly, or a subclass that fails to provide one, triggers this.
Source
Thrown at lib/extras.py:73
# Expose range-related objects
from psycopg2._range import ( # noqa
Range, NumericRange, DateRange, DateTimeRange, DateTimeTZRange,
register_range, RangeAdapter, RangeCaster)
# Expose ipaddress-related objects
from psycopg2._ipaddress import register_ipaddress # noqa
class DictCursorBase(_cursor):
"""Base class for all dict-like cursors."""
def __init__(self, *args, **kwargs):
if 'row_factory' in kwargs:
row_factory = kwargs['row_factory']
del kwargs['row_factory']
else:
raise NotImplementedError(
"DictCursorBase can't be instantiated without a row factory.")
super().__init__(*args, **kwargs)
self._query_executed = False
self._prefetch = False
self.row_factory = row_factory
def fetchone(self):
if self._prefetch:
res = super().fetchone()
if self._query_executed:
self._build_index()
if not self._prefetch:
res = super().fetchone()
return res
def fetchmany(self, size=None):
if self._prefetch:
res = super().fetchmany(size)View on GitHub (pinned to 3a6d9d6ddc)
Solutions
- Use the concrete classes DictCursor or RealDictCursor via the connection_factory or cursor_factory argument instead of DictCursorBase.
- If subclassing DictCursorBase, pass row_factory=<callable> as a keyword to __init__ (the code pops it from kwargs at line 69-71).
- Model your subclass on DictCursor, which sets its own tuple_factory and row_factory.
Example fix
// before cur = conn.cursor(cursor_factory=DictCursorBase) // after from psycopg2.extras import DictCursor cur = conn.cursor(cursor_factory=DictCursor)
Defensive patterns
Strategy: type-guard
Validate before calling
from psycopg2.extras import DictCursor, RealDictCursor # use concrete classes # Never instantiate DictCursorBase directly; choose a concrete cursor.
Type guard
def is_usable_cursor_factory(cf) -> bool:
from psycopg2.extras import DictCursorBase
return isinstance(cf, type) and issubclass(cf, _cursor) and cf is not DictCursorBase Try / catch
try:
cur = conn.cursor(cursor_factory=cf)
except NotImplementedError:
cur = conn.cursor() # fall back to default cursor Prevention
- Use DictCursor or RealDictCursor; treat DictCursorBase as abstract.
- When subclassing DictCursorBase, always pass row_factory.
When it happens
Trigger: Calling DictCursorBase(...) directly, or defining a subclass without setting/ passing a row_factory. The normal subclasses (DictCursor, RealDictCursor) inject a row_factory internally, so this error indicates direct misuse or an incomplete subclass.
Common situations: A developer tries to build a custom dict-like cursor by subclassing DictCursorBase but forgets the row_factory. Also seen when someone instantiates DictCursorBase believing it is a usable cursor.
Related errors
- RangeAdapter must be subclassed overriding its name or the g
- the query contains more than one '%s' placeholder
- the query doesn't contain any '%s' placeholder
AI-assisted analysis of psycopg/psycopg2@3a6d9d6ddc (2026-08-04).
Data as JSON: /data/errors/fe5eba21443273fe.json.
Report an issue: GitHub.