django/django · error · TypeError
Lexeme value must be a string, got {value.__class__.__name__
Error message
Lexeme value must be a string, got {value.__class__.__name__}. What it means
After the empty-string check, `Lexeme.__init__` (search.py:467-470) verifies `isinstance(value, str)` and raises `TypeError` if not, naming the actual class. This catches non-string scalars (int, None, bytes) that would otherwise fail during SQL quoting. The ordering of checks means a non-string non-empty value (e.g. 0, None, an int) reaches this branch.
Source
Thrown at django/contrib/postgres/search.py:468
def __and__(self, other):
return self._combine(other, self.BITAND, False)
def __rand__(self, other):
return self._combine(other, self.BITAND, True)
class Lexeme(LexemeCombinable, Value):
_output_field = SearchQueryField()
def __init__(
self, value, output_field=None, *, invert=False, prefix=False, weight=None
):
if value == "":
raise ValueError("Lexeme value cannot be empty.")
if not isinstance(value, str):
raise TypeError(
f"Lexeme value must be a string, got {value.__class__.__name__}."
)
if weight is not None and (
not isinstance(weight, str) or weight.lower() not in {"a", "b", "c", "d"}
):
raise ValueError(
f"Weight must be one of 'A', 'B', 'C', and 'D', got {weight!r}."
)
self.prefix = prefix
self.invert = invert
self.weight = weight
super().__init__(value, output_field=output_field)
def as_sql(self, compiler, connection):
param = quote_lexeme(self.value)
label = ""View on GitHub (pinned to b5388a3a80)
Solutions
- Pass a string: `Lexeme(str(value))` only after confirming the value is non-empty.
- Pull the right attribute: `Lexeme(doc.title)` instead of `Lexeme(doc)`.
- Decode bytes to str before passing.
Example fix
// before Lexeme(product.id) // after Lexeme(str(product.name))
Defensive patterns
Strategy: type-guard
Validate before calling
if not isinstance(value, str):
raise TypeError(f'Lexeme value must be str, got {type(value).__name__}')
lex = Lexeme(value) Type guard
def is_str(v) -> bool:
return isinstance(v, str) Try / catch
try:
lex = Lexeme(value)
except TypeError as e:
if 'must be a string' in str(e):
lex = Lexeme(str(value))
else:
raise Prevention
- Pull the string attribute off objects before passing (e.g. doc.title, not doc).
- Decode bytes to str upstream.
- Validate API payloads that feed into Lexeme construction.
When it happens
Trigger: Calling `Lexeme(123)`, `Lexeme(None)`, `Lexeme(b'bytes')`, or `Lexeme(some_object)` where the value is not a string. Note: `Lexeme('')` raises the empty error, not this one.
Common situations: Passing an integer ID instead of text; passing None from an optional field; bytes vs str confusion (Python 3); passing a model instance instead of one of its string attributes.
Related errors
- SearchVector can only be combined with other SearchVector in
- SearchQuery can only be combined with other SearchQuery inst
- A Lexeme can only be combined with another Lexeme, got {othe
- BloomIndex.columns must be a list or tuple.
- AddConstraintNotValid.constraint must be a check constraint.
AI-assisted analysis of django/django@b5388a3a80 (2026-08-10).
Data as JSON: /api/errors/e00935e3dff53ff8.
Report an issue: GitHub.