cocoindex-io/cocoindex · error · ValueError

Unsupported record type: {self.record_type}

Error message

Unsupported record type: {self.record_type}

What it means

RecordType.fields can extract field metadata only from dataclasses, NamedTuples, and Pydantic models — the types is_record_type recognizes. If a RecordType was constructed for some other type, iterating .fields falls through all branches and raises ValueError.

Source

Thrown at python/cocoindex/_internal/datatype.py:162

                yield RecordFieldInfo(
                    name=name,
                    type_hint=type_hints.get(name, Any),
                    default_value=defaults.get(name, inspect.Parameter.empty),
                    description=None,
                )
        elif is_pydantic_model(self.record_type):
            model_fields = getattr(self.record_type, "model_fields", {})
            for name, field_info in model_fields.items():
                yield RecordFieldInfo(
                    name=name,
                    type_hint=type_hints.get(name, Any),
                    default_value=field_info.default
                    if field_info.default is not ...
                    else inspect.Parameter.empty,
                    description=field_info.description,
                )
        else:
            raise ValueError(f"Unsupported record type: {self.record_type}")


class UnionType(NamedTuple):
    """
    Any union type, e.g. T1 | T2 | ..., etc.
    """

    variant_types: list[Any]


class MappingType(NamedTuple):
    """
    Any dict type, e.g. dict[T1, T2], Mapping[T1, T2], etc.
    """

    key_type: Any
    value_type: Any

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Convert the type to a @dataclass, typing.NamedTuple, or pydantic.BaseModel
  2. Check is_record_type(t) before constructing RecordType in custom analysis code
  3. If using TypedDict, switch to a dataclass with equivalent fields

Example fix

// before
class Row(TypedDict):
    id: int

// after
@dataclasses.dataclass
class Row:
    id: int
Defensive patterns

Strategy: type-guard

Validate before calling

from cocoindex._internal.datatype import is_record_type
if not is_record_type(Row):
    raise TypeError(f"{Row} must be dataclass/NamedTuple/pydantic model")

Type guard

def is_valid_record(t: type) -> bool:
    return dataclasses.is_dataclass(t) or hasattr(t, "_fields") or (
        PYDANTIC_AVAILABLE and issubclass(t, pydantic.BaseModel))

Try / catch

try:
    fields = list(RecordType(record_type=Row).fields)
except ValueError as e:
    logging.error("record type unsupported: %s", e)
    Row = dataclasses.dataclass(Row)  # or switch to a supported class

Prevention

When it happens

Trigger: Passing a plain class, TypedDict, attrs class (without recognition), or a NamedTuple-like object lacking _fields into a code path that wraps it in RecordType and iterates fields; or is_record_type and fields going out of sync (e.g. a type that passed the record check but whose specific kind isn't handled).

Common situations: Using TypedDict for schema rows (not supported); defining a custom struct class and expecting it to be treated as a record; a library upgrade changing the recognized record kinds.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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