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

from_class derives the target's columns from the record type's fields, which requires a dataclass, NamedTuple, or Pydantic model. If record_type is any other type (str, dict, plain class, None), is_record_type fails and a TypeError is raised naming the actual type received.

Source

Thrown at python/cocoindex/connectors/bigquery/_target.py:148

    @classmethod
    async def from_class(
        cls,
        record_type: type[RowT],
        primary_key: list[str],
        *,
        column_overrides: dict[str, BigQueryType] | None = None,
    ) -> "TableSchema[RowT]":
        """
        Create a TableSchema from a record type.

        Args:
            record_type: A dataclass, NamedTuple, or Pydantic model.
            primary_key: List of column names that form the primary key.
            column_overrides: Optional per-column BigQueryType overrides.
        """
        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, BigQueryType] | None,
    ) -> dict[str, ColumnDef]:
        """Convert a record type to a dict of column name to ColumnDef."""
        record_info = RecordType(record_type)
        columns: dict[str, ColumnDef] = {}

        for field in record_info.fields:
            override = column_overrides.get(field.name) if column_overrides else None
            type_info = analyze_type_info(field.type_hint)

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Pass an actual dataclass, NamedTuple, or Pydantic model class (not a string, dict, or instance).
  2. Add the @dataclass decorator if you intended a dataclass but forgot it.
  3. Convert a TypedDict to NamedTuple or dataclass, or use Pydantic BaseModel.
  4. Ensure you pass the class object itself, e.g. Row, not Row() or 'Row'.

Example fix

// before
target = table_target(client, "proj.ds.tbl", {"id": "INT64"}, primary_key=["id"])

// after
@dataclass
class Row:
    id: int
    name: str
target = table_target(client, "proj.ds.tbl", Row, primary_key=["id"])
Defensive patterns

Strategy: type-guard

Validate before calling

import dataclasses
assert dataclasses.is_dataclass(Row), "record_type must be a dataclass/NamedTuple/Pydantic model"

Type guard

def is_record_type(t: object) -> bool:
    import dataclasses
    if dataclasses.is_dataclass(t):
        return True
    if isinstance(t, type) and issubclass(t, tuple):
        return hasattr(t, "_fields")
    try:
        from pydantic import BaseModel
        return isinstance(t, type) and issubclass(t, BaseModel)
    except ImportError:
        return False

Try / catch

try:
    target = table_target(client, table, record_type, primary_key=pk)
except TypeError as e:
    logger.error("bad record_type: %s", e)
    raise

Prevention

When it happens

Trigger: Calling table_target(..., record_type='MyRow') passing the class name as a string; passing a dict of column specs instead of a typed record; passing a plain (non-dataclass) class or a TypedDict.

Common situations: Confusing TypedDict with NamedTuple; forgetting the @dataclass decorator; passing an instance instead of the class; stringly-typed configuration of record types.

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


AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08). Data as JSON: /api/errors/652611378069abfe. Report an issue: GitHub.