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 Snowflake target's `from_class` requires `record_type` to be a structured record type (dataclass, NamedTuple, or Pydantic model) from which column definitions can be derived. Passing any other type (dict, plain class, None, etc.) fails the `is_record_type` check and raises a TypeError. This enforces that table columns can be introspected from field annotations.
Source
Thrown at python/cocoindex/connectors/snowflake/_target.py:141
@classmethod
async def from_class(
cls,
record_type: type[RowT],
primary_key: list[str],
*,
column_overrides: dict[str, SnowflakeType] | 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 SnowflakeType 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, SnowflakeType] | 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 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
- Decorate the class with @dataclasses.dataclass (with type annotations on all fields) and pass that class.
- Use a typing.NamedTuple subclass with annotated fields instead.
- If using Pydantic, ensure it is a supported (BaseModel) class and that pydantic is installed.
- Check for typos — e.g. passing an instance or the module instead of the class.
Example fix
// before
spec = {"id": int, "text": str}
target = snowflake.table_target(record_type=spec, ...)
// after
@dataclasses.dataclass
class RowSpec:
id: int
text: str
target = snowflake.table_target(record_type=RowSpec, ...) Defensive patterns
Strategy: type-guard
Validate before calling
import dataclasses, typing
from pydantic import BaseModel
def is_valid_record_type(rt) -> bool:
return dataclasses.is_dataclass(rt) or (
isinstance(rt, type) and issubclass(rt, tuple) and hasattr(rt, "_fields")
) or (isinstance(rt, type) and issubclass(rt, BaseModel))
assert is_valid_record_type(RowSpec), "record_type must be a dataclass/NamedTuple/Pydantic model" Type guard
def is_record_type(rt: object) -> TypeGuard[type]:
import dataclasses
from pydantic import BaseModel
return (
isinstance(rt, type)
and (dataclasses.is_dataclass(rt) or issubclass(rt, BaseModel)
or (issubclass(rt, tuple) and hasattr(rt, '_fields')))
) Try / catch
try:
target = snowflake.table_target(record_type=RowSpec, ...)
except TypeError as e:
if "record_type must be a record type" in str(e):
raise ConfigError("Define RowSpec as @dataclass / NamedTuple / BaseModel") from e
raise Prevention
- Always declare record types with @dataclasses.dataclass and fully annotated fields.
- Avoid TypedDict — it is not accepted as a record type here.
- Unit-test target construction at import time to catch schema mistakes early.
When it happens
Trigger: Calling `SnowflakeTableTarget.from_class(record_type=...)` (directly or via `table_target`) with a dict, a non-annotated plain class, a TypedDict, None, or any object not recognized as a dataclass/NamedTuple/Pydantic model.
Common situations: Passing a TypedDict (not supported), passing a dict describing columns manually, forgetting the @dataclass decorator, or using a Pydantic v1 model where only v2-style models are detected.
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
- Unsupported type for TypeChecker: {tp}
- use_mount() requires a ComponentSubpath when the function ha
- LiveComponent classes cannot be used with use_mount(). Use m
- mount() requires a ComponentSubpath when the function has no
- mount_each() requires a ComponentSubpath when the function h
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/59bc3da2e3579556.
Report an issue: GitHub.