{"record":{"id":"7d0f0584a0c3b131","repo":"cocoindex-io/cocoindex","slug":"row-row-id-r-schema-declares-named-vectors-so","errorCode":null,"errorMessage":"Row {row.id!r}: schema declares named vectors ({sorted(vector_field_names)}) but row.vector is not a dict.","messagePattern":"Row (.+?): schema declares named vectors \\((.+?)\\) but row\\.vector is not a dict\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/cocoindex/connectors/turbopuffer/_target.py","lineNumber":203,"sourceCode":"\n    id: _RowId\n    vector: Sequence[float] | np.ndarray | dict[str, Sequence[float] | np.ndarray]\n    attributes: dict[str, Any] | None = None\n\n\ndef _vector_to_list(v: Sequence[float] | np.ndarray) -> list[float]:\n    if isinstance(v, np.ndarray):\n        return v.tolist()  # type: ignore[no-any-return]\n    return list(v)\n\n\ndef _row_to_upsert(row: Row, schema: NamespaceSchema) -> dict[str, Any]:\n    \"\"\"Convert a Row to the dict shape turbopuffer's write API expects.\"\"\"\n    out: dict[str, Any] = {\"id\": row.id}\n\n    if isinstance(schema.vectors, _ResolvedNamedVectorsDef):\n        vector_field_names = set(schema.vectors.vectors)\n        if not isinstance(row.vector, dict):\n            raise ValueError(\n                f\"Row {row.id!r}: schema declares named vectors \"\n                f\"({sorted(vector_field_names)}) but row.vector is not a dict.\"\n            )\n        missing = vector_field_names - set(row.vector)\n        if missing:\n            raise ValueError(\n                f\"Row {row.id!r}: missing vector fields {sorted(missing)}.\"\n            )\n        for name, vec in row.vector.items():\n            out[name] = _vector_to_list(vec)\n    else:\n        vector_field_names = {_DEFAULT_VECTOR_FIELD}\n        if isinstance(row.vector, dict):\n            raise ValueError(\n                f\"Row {row.id!r}: schema declares a single unnamed vector but \"\n                f\"row.vector is a dict.\"\n            )","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/connectors/turbopuffer/_target.py#L185-L221","documentation":"The turbopuffer connector's `_row_to_upsert` builds the wire payload for each Row. When the namespace schema declares named vectors (a dict of vector fields), the connector requires `row.vector` to be a dict mapping vector field name to vector data. Passing anything else (a single sequence, ndarray, or scalar) makes the row shape incompatible with the schema, so a ValueError is raised before any network call.","triggerScenarios":"Declaring a NamespaceSchema with `vectors={\"title_vec\": ..., \"body_vec\": ...}` (a _ResolvedNamedVectorsDef) but constructing Row(id=..., vector=[0.1, 0.2]) or Row(id=..., vector=np.array([...])) instead of a dict, then calling reconcile / writing the row.","commonSituations":"Migrating a namespace from a single unnamed vector to named vectors while reusing the old Row construction code; copying examples for single-vector namespaces into a multi-vector app; passing an embedding returned by a single-vector model directly into a named-vector schema.","solutions":["Wrap the vector in a dict keyed by the declared vector field name: Row(id=..., vector={\"title_vec\": [0.1, 0.2], \"body_vec\": [...]})","Check `sorted(schema.vectors.vectors)` to confirm the exact field names the schema expects before building rows.","If you actually only need one vector, change the schema to a single VectorDef instead of a named-vectors dict so a plain sequence is accepted."],"exampleFix":"// before\nrow = Row(id=42, vector=np.array([0.1, 0.2, 0.3]))\n\n// after\nrow = Row(id=42, vector={\"title_vec\": np.array([0.1, 0.2, 0.3]), \"body_vec\": [0.4, 0.5, 0.6]})","handlingStrategy":"type-guard","validationCode":"named = isinstance(schema.vectors, _ResolvedNamedVectorsDef)\nif named and not isinstance(row.vector, dict):\n    raise TypeError(f\"Row {row.id}: expected dict of named vectors\")","typeGuard":"def is_named_vector_dict(v: object) -> TypeGuard[dict[str, Sequence[float] | np.ndarray]]:\n    return isinstance(v, dict)","tryCatchPattern":"try:\n    out = await component.reconcile(row)\nexcept ValueError as e:\n    if \"row.vector is not a dict\" in str(e):\n        row = replace(row, vector=as_named_dict(row.vector, schema))\n    else:\n        raise","preventionTips":["Match Row.vector shape to the schema: dict for named vectors, plain sequence for single vector","Centralize Row construction in one helper that branches on the schema kind","Add a unit test asserting row shape against schema for both schema kinds"],"tags":["python","vector","schema-mismatch","turbopuffer"],"backgroundTag":"type-mismatch","analyzedSha":"e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b","analyzedAt":"2026-09-08T15:59:19.997Z","contentChangedAt":"2026-09-08T15:59:19.997Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}