cocoindex-io/cocoindex · error

row_count must be positive

Error message

row_count must be positive

What it means

Raised by _delete_sql in the BigQuery connector when asked to build a DELETE statement for a non-positive number of rows. The generated SQL uses one positional query parameter (@p0, @p1, ...) per row to delete, so row_count must be at least 1; 0 or negative means the caller computed an empty or invalid batch.

Source

Thrown at python/cocoindex/connectors/bigquery/_target.py:314

        f"ON {on_clause}",
    ]

    if non_pk_cols:
        update_list = ", ".join(f"`{c}` = source.`{c}`" for c in non_pk_cols)
        sql_parts.append(f"WHEN MATCHED THEN UPDATE SET {update_list}")

    sql_parts.append(
        f"WHEN NOT MATCHED THEN INSERT ({insert_cols}) VALUES ({insert_values})"
    )
    return " ".join(sql_parts)


def _delete_sql(
    qualified_table_name: str, table_schema: TableSchema[Any], *, row_count: int
) -> str:
    pk_cols = table_schema.primary_key
    if row_count <= 0:
        raise ValueError("row_count must be positive")

    if len(pk_cols) == 1:
        markers = ", ".join(f"@p{i}" for i in range(row_count))
        return f"DELETE FROM {qualified_table_name} WHERE `{pk_cols[0]}` IN ({markers})"

    row_clauses = []
    param_idx = 0
    for _ in range(row_count):
        and_parts = []
        for pk in pk_cols:
            and_parts.append(f"`{pk}` = @p{param_idx}")
            param_idx += 1
        row_clauses.append(f"({' AND '.join(and_parts)})")
    return f"DELETE FROM {qualified_table_name} WHERE {' OR '.join(row_clauses)}"


def _encode_value(col: ColumnDef, value: Any) -> Any:
    if value is None:

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Ensure the caller skips the DELETE entirely when the batch is empty (guard with `if row_count > 0` before calling _delete_sql).
  2. Check what feeds row_count in _apply_actions — inspect why an empty or negative key batch reached the delete path.
  3. Report/fix the batching bug if a non-empty action list yields row_count<=0.

Example fix

// before
sql = _delete_sql(qualified, schema, row_count=len(keys))
// after
if keys:
    sql = _delete_sql(qualified, schema, row_count=len(keys))
Defensive patterns

Strategy: validation

Validate before calling

if not keys:
    return  # or skip building the DELETE
assert len(keys) > 0, "delete batch must be non-empty"

Prevention

When it happens

Trigger: Calling _delete_sql (via _apply_actions during a target sync) with row_count=0 or negative, e.g. when a delete batch contains no primary keys but the delete path is still invoked.

Common situations: A sync run where all declared rows were removed and an empty delete batch is generated; bugs in batching logic that pass len(keys)=0; upstream code changes that no longer guard against empty batches.

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


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