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
Surrealdb table targets are built from a 'record type' — a dataclass, NamedTuple, or Pydantic model — which supplies the row schema. `from_class` checks `is_record_type(record_type)` and refuses anything else so that column extraction has a well-defined schema to read from. Passing a plain dict, TypedDict, or arbitrary class triggers this TypeError.
Source
Thrown at python/cocoindex/connectors/surrealdb/_target.py:379
async def from_class(
cls,
record_type: type[RowT],
*,
column_overrides: dict[str, SurrealType | 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 SurrealDB types.
Args:
record_type: A record type (dataclass, NamedTuple, or Pydantic model).
column_overrides: Optional dict mapping field names to SurrealType 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, row_type=record_type)
@staticmethod
async def _columns_from_record_type(
record_type: type,
column_overrides: dict[str, SurrealType | res_schema.VectorSchemaProvider]
| None,
) -> dict[str, ColumnDef]:
"""Convert a record type to a dict of field name -> ColumnDef."""
record_info = RecordType(record_type)
columns: dict[str, ColumnDef] = {}
for field in record_info.fields:
type_info = analyze_type_info(field.type_hint)View on GitHub (pinned to e84aa99b32)
Solutions
- Decorate the class with `@dataclasses.dataclass` (or make it a `typing.NamedTuple` subclass, or a Pydantic `BaseModel`) and pass that class.
- Verify you are passing the class itself, not an instance (`MyRecord`, not `MyRecord(...)`).
- If you were using a TypedDict, convert it to a dataclass with the same fields.
- Print `type(record_type)` from the error message to confirm what was actually passed.
Example fix
// before
from typing import TypedDict
class User(TypedDict):
name: str
age: int
target = await surrealdb.TableTarget.from_class(record_type=User)
// after
import dataclasses
class User:
name: str
age: int
target = await surrealdb.TableTarget.from_class(record_type=dataclasses.dataclass(User) if not dataclasses.is_dataclass(User) else User) Defensive patterns
Strategy: type-guard
Validate before calling
import dataclasses, typing
from pydantic import BaseModel
def is_record_type(t) -> bool:
return dataclasses.is_dataclass(t) or (isinstance(t, type) and issubclass(t, typing.NamedTuple)) or (isinstance(t, type) and issubclass(t, BaseModel))
assert is_record_type(MyRecord), f"{type(MyRecord)} is not a dataclass/NamedTuple/Pydantic model" Type guard
def is_record_type(t: object) -> bool:
import dataclasses, typing
from pydantic import BaseModel
return (
dataclasses.is_dataclass(t)
or (isinstance(t, type) and issubclass(t, typing.NamedTuple))
or (isinstance(t, type) and issubclass(t, BaseModel))
) Try / catch
try:
target = await surrealdb.TableTarget.from_class(record_type=record_type)
except TypeError as e:
if "record_type must be a record type" in str(e):
raise ValueError(f"Fix record_type definition: got {type(record_type)}") from e
raise Prevention
- Always declare row schemas with @dataclass, typing.NamedTuple, or pydantic.BaseModel.
- Pass the class, never an instance, to from_class.
- Add a unit test asserting from_class accepts your schema class.
- Avoid TypedDict for schema definitions passed to this API.
When it happens
Trigger: Calling `TableTarget.from_class(record_type=...)` (or the declare-table entry that delegates to it) with a plain `dict`, a `TypedDict`, a plain `class` without dataclass/NamedTuple/Pydantic decoration, a generic alias, or `None`.
Common situations: Developers coming from dict-based ORMs pass a `TypedDict` thinking it qualifies; forgetting the `@dataclass` decorator; passing a Pydantic model *class* where an instance-based schema was expected elsewhere; autocompletion picking the wrong `from_class` overload.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- record_type must be a record type (dataclass, NamedTuple, Py
- Unsupported record type: {self.record_type}
- timeout() requires a datetime.timedelta
- {type(obj).__name__} cannot be used as a memoization key. Th
- Unsupported type for memoization key: {type(obj)!r}. Provide
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/a6a547f1df551053.
Report an issue: GitHub.