cocoindex-io/cocoindex · error · TypeError
record_type must be a record type (dataclass, NamedTuple, Py
Error message
record_type must be a record type (dataclass, NamedTuple, Pydantic model), got {type(record_type)} What it means
The `table_target`/`from_class` factory for the SQLite connector requires `record_type` to be a supported record type (dataclass, NamedTuple, or Pydantic model). The library validates this with `is_record_type()` and raises `TypeError` when any other value (e.g. a plain class, dict, or instance) is passed, because it relies on record introspection to derive column names and types.
Source
Thrown at python/cocoindex/connectors/sqlite/_target.py:358
record_type: type[RowT],
primary_key: list[str],
*,
column_overrides: dict[str, SqliteType | res_schema.VectorSchemaProvider]
| None = None,
) -> "TableSchema[RowT]":
"""
Create a TableSchema from a record type (dataclass, NamedTuple, or Pydantic model).
Python types are automatically mapped to SQLite types.
Args:
record_type: A record type (dataclass, NamedTuple, or Pydantic model).
primary_key: List of column names that form the primary key.
column_overrides: Optional dict mapping column names to SqliteType or
VectorSchemaProvider to override the default type mapping.
"""
if not is_record_type(record_type):
raise TypeError(
f"record_type must be a record type (dataclass, NamedTuple, Pydantic model), "
f"got {type(record_type)}"
)
columns = await cls._columns_from_record_type(record_type, column_overrides)
return cls(columns, primary_key, row_type=record_type)
@staticmethod
async def _columns_from_record_type(
record_type: type,
column_overrides: dict[str, SqliteType | res_schema.VectorSchemaProvider]
| None,
) -> dict[str, ColumnDef]:
"""Convert a record type to a dict of column name -> ColumnDef."""
record_info = RecordType(record_type)
columns: dict[str, ColumnDef] = {}
for rec_field in record_info.fields:
override = (View on GitHub (pinned to e84aa99b32)
Solutions
- Annotate the class with `@dataclass` (or make it a NamedTuple / subclass a Pydantic BaseModel) and pass the class itself, not an instance
- If you cannot change the type, build the table schema with explicit `SqliteColumn` definitions instead of deriving them from a record type
- Check that the import points at the class, not a module or instance variable
Example fix
// before
row = MyRow(id=1, text="hi")
target = sqlite.table_target("docs", record_type=row, primary_key=["id"])
// after
@dataclass
class MyRow:
id: int
text: str
target = sqlite.table_target("docs", record_type=MyRow, primary_key=["id"]) Defensive patterns
Strategy: type-guard
Validate before calling
import dataclasses from cocoindex.connectors.sqlite import _target # or use the public helper assert dataclasses.is_dataclass(MyRow) or issubclass(MyRow, tuple) or issubclass(MyRow, BaseModel)
Type guard
def is_record_type_ok(rt: object) -> bool:
import dataclasses
from pydantic import BaseModel
return (
isinstance(rt, type)
and (dataclasses.is_dataclass(rt) or issubclass(rt, tuple) or issubclass(rt, BaseModel))
) Try / catch
try:
target = sqlite.table_target("docs", record_type=MyRow, primary_key=["id"])
except TypeError as e:
if "record_type must be a record type" in str(e):
raise ValueError("Pass the record class (dataclass/NamedTuple/Pydantic), not an instance") from e
raise Prevention
- Always pass the class, never an instance, as record_type
- Prefer @dataclass for row types; avoid TypedDict, which is not supported
- Check the primary_key names exist as fields on the record type
When it happens
Trigger: Calling `SqliteTarget.from_class(record_type=...)` (or `table_target(...)` with a record-based schema) with a value that is not a dataclass, NamedTuple, or Pydantic model — e.g. a plain `class`, a `dict`, a TypedDict, or an *instance* of a dataclass instead of the class itself.
Common situations: Developers pass a TypedDict (looks record-like but is not supported), pass an instantiated row object instead of the type, or use a plain class without the `@dataclass` decorator. Also common when a refactor changes a dataclass into a regular class or attrs model.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- ZvecFtsType on column {name!r} requires a str field, got {ty
- LiveComponent classes cannot be used with use_mount(). Use m
- Context key '{key}': expected {t.__name__}, got {type(value)
- expected None{loc}, got {type(value).__name__}
- expected {tp}{loc}, got {type(value).__name__}: {value!r}
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/8531f2dbbbb5138e.
Report an issue: GitHub.