cocoindex-io/cocoindex · error · ValueError

Row {row.id!r}: missing vector fields {sorted(missing)}.

Error message

Row {row.id!r}: missing vector fields {sorted(missing)}.

What it means

For a named-vectors turbopuffer schema, every declared vector field must be present in `row.vector`. `_row_to_upsert` computes `vector_field_names - set(row.vector)`; if any declared field is absent it raises this ValueError listing the missing names. Turbopuffer's write API needs a value for each declared vector, so partial dicts are rejected client-side.

Source

Thrown at python/cocoindex/connectors/turbopuffer/_target.py:208

def _vector_to_list(v: Sequence[float] | np.ndarray) -> list[float]:
    if isinstance(v, np.ndarray):
        return v.tolist()  # type: ignore[no-any-return]
    return list(v)


def _row_to_upsert(row: Row, schema: NamespaceSchema) -> dict[str, Any]:
    """Convert a Row to the dict shape turbopuffer's write API expects."""
    out: dict[str, Any] = {"id": row.id}

    if isinstance(schema.vectors, _ResolvedNamedVectorsDef):
        vector_field_names = set(schema.vectors.vectors)
        if not isinstance(row.vector, dict):
            raise ValueError(
                f"Row {row.id!r}: schema declares named vectors "
                f"({sorted(vector_field_names)}) but row.vector is not a dict."
            )
        missing = vector_field_names - set(row.vector)
        if missing:
            raise ValueError(
                f"Row {row.id!r}: missing vector fields {sorted(missing)}."
            )
        for name, vec in row.vector.items():
            out[name] = _vector_to_list(vec)
    else:
        vector_field_names = {_DEFAULT_VECTOR_FIELD}
        if isinstance(row.vector, dict):
            raise ValueError(
                f"Row {row.id!r}: schema declares a single unnamed vector but "
                f"row.vector is a dict."
            )
        out[_DEFAULT_VECTOR_FIELD] = _vector_to_list(row.vector)

    reserved = {"id"} | vector_field_names
    if row.attributes:
        for k, v in row.attributes.items():

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Include an entry for every declared vector field in the row.vector dict, using the exact names from sorted(schema.vectors.vectors).
  2. Fix key typos by copying names from the error message or schema definition rather than typing them by hand.
  3. If the field is optional for this row, provide a zero/dummy vector of the declared size, or restructure the schema so that field is a separate namespace.

Example fix

// before
Row(id=1, vector={"title_vec": embed(title)})

// after
Row(id=1, vector={"title_vec": embed(title), "body_vec": embed(body)})
Defensive patterns

Strategy: validation

Validate before calling

declared = set(schema.vectors.vectors)
missing = declared - set(row.vector)
assert not missing, f"Row {row.id} missing vector fields: {missing}"

Type guard

def has_all_vector_fields(v: dict, names: set[str]) -> TypeGuard[dict[str, Sequence[float]]]:
    return names <= set(v)

Try / catch

try:
    await component.reconcile(row)
except ValueError as e:
    m = re.search(r"missing vector fields \[(.*)\]", str(e))
    if m:
        row = fill_missing_fields(row, ast.literal_eval(m.group(1)))
    else:
        raise

Prevention

When it happens

Trigger: Schema declares vectors {"title_vec", "body_vec"} but Row is built as Row(id=..., vector={"title_vec": [...]}) — the 'body_vec' key is missing when reconcile serializes the row.

Common situations: Adding a new vector field to the schema without updating row-building code; computing one embedding lazily and omitting the key on failure; a typo in a dict key so the declared name isn't matched.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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