psycopg/psycopg2 · error · TypeError
context must be a connection or a cursor
Error message
context must be a connection or a cursor
What it means
Raised by Literal.as_string() (lib/sql.py:385) when the context argument is neither a psycopg2 connection nor a cursor. Literal must adapt the wrapped Python value through psycopg2's adaptation machinery, which needs the connection's encoding and registered type adapters - hence a live connection (or a cursor, which exposes .connection) is mandatory. (Note: SQL.as_string and Identifier.as_string ignore context, so this only bites Literal rendering.)
Source
Thrown at lib/sql.py:385
>>> s2 = sql.Literal("ba'r")
>>> s3 = sql.Literal(42)
>>> print(sql.SQL(', ').join([s1, s2, s3]).as_string(conn))
'foo', 'ba''r', 42
"""
@property
def wrapped(self):
"""The object wrapped by the `!Literal`."""
return self._wrapped
def as_string(self, context):
# is it a connection or cursor?
if isinstance(context, ext.connection):
conn = context
elif isinstance(context, ext.cursor):
conn = context.connection
else:
raise TypeError("context must be a connection or a cursor")
a = ext.adapt(self._wrapped)
if hasattr(a, 'prepare'):
a.prepare(conn)
rv = a.getquoted()
if isinstance(rv, bytes):
rv = rv.decode(ext.encodings[conn.encoding])
return rv
class Placeholder(Composable):
"""A `Composable` representing a placeholder for query parameters.
If the name is specified, generate a named placeholder (e.g. ``%(name)s``),
otherwise generate a positional placeholder (e.g. ``%s``).
View on GitHub (pinned to 3a6d9d6ddc)
Solutions
- Pass an actual psycopg2 connection or cursor to as_string(): sql.Literal(v).as_string(conn).
- If you only need static placeholder text, use SQL/Identifier/Placeholder whose as_string ignores context.
- In tests, use a real (possibly in-memory or temp-DB) connection or avoid rendering Literals offline.
Example fix
// before lit = sql.Literal(42).as_string(None) // after lit = sql.Literal(42).as_string(conn)
Defensive patterns
Strategy: type-guard
Validate before calling
from psycopg2 import extensions
def render_literal(value, ctx):
if not isinstance(ctx, (extensions.connection, extensions.cursor)):
raise TypeError('a psycopg2 connection or cursor is required to render a Literal')
return sql.Literal(value).as_string(ctx) Type guard
from psycopg2 import extensions
def is_literal_context(ctx) -> bool:
return isinstance(ctx, (extensions.connection, extensions.cursor)) Prevention
- Always thread the live connection/cursor through to any code that renders Literals.
- For offline rendering, prefer SQL/Identifier/Placeholder whose as_string ignores context.
- In tests, stand up a real (temp) connection rather than passing None.
When it happens
Trigger: sql.Literal(42).as_string(None), .as_string('conn'), .as_string(''), or omitting the argument. Also calling as_string on a Literal during offline/unit-test rendering with no live connection.
Common situations: Pre-rendering SQL templates outside any connection scope; passing the wrong object (a string DSN, a pool wrapper); unit tests that try to render Literals without a real psycopg2 connection.
Related errors
- Identifier cannot be empty
- SQL identifier parts must be strings
- expected string or None as name, got {name!r}
- no format specification supported by SQL
- no format conversion supported by SQL
AI-assisted analysis of psycopg/psycopg2@3a6d9d6ddc (2026-08-04).
Data as JSON: /data/errors/d195ac29b563f913.json.
Report an issue: GitHub.