cocoindex-io/cocoindex · error · ValueError
Cannot specify both row_factory and row_type
Error message
Cannot specify both row_factory and row_type
What it means
PostgresSource row customization accepts either a row_factory callable or a row_type record class, but not both, since each fully determines how rows are built and which columns are resolved. Specifying both is ambiguous, so __init__ raises ValueError immediately.
Source
Thrown at python/cocoindex/connectors/postgres/_source.py:205
table_name: str,
columns: Sequence[str] | None = ...,
pg_schema_name: str | None = ...,
row_factory: None = ...,
row_type: type[RowT],
) -> None: ...
def __init__(
self,
pool: asyncpg.Pool,
*,
table_name: str,
columns: Sequence[str] | None = None,
pg_schema_name: str | None = None,
row_factory: Callable[[dict[str, Any]], RowT] | None = None,
row_type: type[RowT] | None = None,
) -> None:
if row_factory is not None and row_type is not None:
raise ValueError("Cannot specify both row_factory and row_type")
# Determine columns based on row_type
resolved_columns: Sequence[str] | None = columns
if row_type is not None:
if not is_record_type(row_type):
raise TypeError(
f"row_type must be a record type (dataclass, NamedTuple, or Pydantic model), "
f"got {row_type}"
)
record_info = RecordType(row_type)
field_names = [f.name for f in record_info.fields]
field_set = frozenset(field_names)
if columns is not None:
# Validate that all specified columns exist in the record type
invalid_cols = [c for c in columns if c not in field_set]
if invalid_cols:
raise ValueError(View on GitHub (pinned to e84aa99b32)
Solutions
- Remove either the row_factory or the row_type argument so only one is passed.
- If you need custom row construction, keep row_factory and drop row_type.
- If you want typed records (dataclass/NamedTuple/Pydantic), keep row_type and delete row_factory.
Example fix
// before src = PostgresSource(table="users", row_factory=build_user, row_type=User) // after src = PostgresSource(table="users", row_type=User)
Defensive patterns
Strategy: validation
Validate before calling
assert not (row_factory is not None and row_type is not None), "Pass only one of row_factory or row_type"
Type guard
def has_conflict(kwargs: dict) -> bool:
return kwargs.get("row_factory") is not None and kwargs.get("row_type") is not None Try / catch
try:
src = PostgresSource(table="t", row_factory=f, row_type=R)
except ValueError as e:
if "both row_factory and row_type" in str(e):
src = PostgresSource(table="t", row_type=R) Prevention
- Pick one row-mapping style per source and standardize on it (prefer row_type).
- Wrap source construction in a helper function that enforces the exclusivity.
- Enable keyword-argument linting/review when copying example snippets.
When it happens
Trigger: Calling PostgresSource(...) with both a non-None row_factory and a non-None row_type argument, e.g. PostgresSource(table='t', row_factory=my_fn, row_type=MyRecord).
Common situations: Developers migrating from a factory function to a typed record leave the old row_factory kwarg in place while adding row_type for type hints; copying example code that sets one option without noticing the other.
Related errors
- Columns {invalid_cols} not found in row_type fields: {field_
- Invalid pgvector dimension: {vector_schema.size}
- expected None{loc}, got {type(value).__name__}
- expected {tp}{loc}, got {type(value).__name__}: {value!r}
- expected tuple{loc}, got {type(value).__name__}
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/f31e5cc27fb97f07.
Report an issue: GitHub.