dotnet/efcore · error · InvalidOperationException

The number of key column types

Error message

The number of key column types ({typesCount}) doesn't match the number of key columns ({columnsCount}) for the data modification operation on '{table}'. Provide the same number of key column types and key columns.

What it means

Thrown when an UpdateData operation supplies KeyColumnTypes whose length differs from KeyColumns. EF needs a one-to-one mapping so it can resolve a type mapping per key parameter.

Solutions

  1. Make keyColumnTypes length equal to keyColumns length, one store type per key column.
  2. Drop keyColumnTypes entirely to fall back on the model.
  3. Re-scaffold the migration so types are written consistently.

Example fix

// before
migrationBuilder.UpdateData(
    table: "Users",
    keyColumns: new[] { "TenantId", "Id" },
    keyColumnTypes: new[] { "int" }, // length 1 != 2
    keyValues: new object[,] { { 1, 10 } },
    columns: new[] { "Name" },
    values: new object[,] { { "Ann" } });

// after
migrationBuilder.UpdateData(
    table: "Users",
    keyColumns: new[] { "TenantId", "Id" },
    keyColumnTypes: new[] { "int", "int" },
    keyValues: new object[,] { { 1, 10 } },
    columns: new[] { "Name" },
    values: new object[,] { { "Ann" } });
Defensive patterns

Strategy: validation

Validate before calling

static void CheckKeyTypeCount(string[] keyColumns, string[]? keyColumnTypes, string table)
{
    if (keyColumnTypes is not null && keyColumnTypes.Length != keyColumns.Length)
        throw new ArgumentException($"{table}: keyColumnTypes length must equal keyColumns length");
}

Prevention

When it happens

Trigger: migrationBuilder.UpdateData(...) with keyColumnTypes: of wrong length. Checked after the row-count check in GenerateModificationCommands(UpdateDataOperation).

Common situations: Hand-edited composite-key update where a key column was added but keyColumnTypes was not updated. SQLite migrations that explicitly declare key types.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/c394428143b2bd3b. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs:1082

        if (operation.Columns.Length != operation.Values.GetLength(1))
        {
            throw new InvalidOperationException(
                RelationalStrings.UpdateDataOperationValuesCountMismatch(
                    operation.Values.GetLength(1), operation.Columns.Length, FormatTable(operation.Table, operation.Schema)));
        }

        if (operation.KeyValues.GetLength(0) != operation.Values.GetLength(0))
        {
            throw new InvalidOperationException(
                RelationalStrings.UpdateDataOperationRowCountMismatch(
                    operation.Values.GetLength(0), operation.KeyValues.GetLength(0), FormatTable(operation.Table, operation.Schema)));
        }

        if (operation.KeyColumnTypes != null
            && operation.KeyColumns.Length != operation.KeyColumnTypes.Length)
        {
            throw new InvalidOperationException(
                RelationalStrings.UpdateDataOperationKeyTypesCountMismatch(
                    operation.KeyColumnTypes.Length, operation.KeyColumns.Length, FormatTable(operation.Table, operation.Schema)));
        }

        if (operation.ColumnTypes != null
            && operation.Columns.Length != operation.ColumnTypes.Length)
        {
            throw new InvalidOperationException(
                RelationalStrings.UpdateDataOperationTypesCountMismatch(
                    operation.ColumnTypes.Length, operation.Columns.Length, FormatTable(operation.Table, operation.Schema)));
        }

        if (operation.KeyColumnTypes == null
            && model == null)
        {
            throw new InvalidOperationException(
                RelationalStrings.UpdateDataOperationNoModel(
                    FormatTable(operation.Table, operation.Schema)));

View on GitHub (pinned to 3a2006ef56)