dotnet/efcore · error · InvalidOperationException

The number of key values ({valuesCount}) doesn't match the n

Error message

The number of key values ({valuesCount}) doesn't match the number of key columns ({columnsCount}) for the data deletion operation on '{table}'. Provide the same number of key values and key columns.

What it means

Thrown inside GenerateModificationCommands(DeleteDataOperation, ...) in src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs:969 (message key DeleteDataOperationValuesCountMismatch). It compares operation.KeyColumns.Length against operation.KeyValues.GetLength(1) and throws InvalidOperationException when they differ. DeleteData builds a WHERE clause per row from the key columns, so the per-row key-value count must equal the key-column count.

Source

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

        }

        builder.Append(sqlBuilder.ToString());
        EndStatement(builder);
    }

    /// <summary>
    ///     Generates the commands that correspond to the given operation.
    /// </summary>
    /// <param name="operation">The data operation to generate commands for.</param>
    /// <param name="model">The model.</param>
    /// <returns>The commands that correspond to the given operation.</returns>
    protected virtual IEnumerable<IReadOnlyModificationCommand> GenerateModificationCommands(
        DeleteDataOperation operation,
        IModel? model)
    {
        if (operation.KeyColumns.Length != operation.KeyValues.GetLength(1))
        {
            throw new InvalidOperationException(
                RelationalStrings.DeleteDataOperationValuesCountMismatch(
                    operation.KeyValues.GetLength(1), operation.KeyColumns.Length, FormatTable(operation.Table, operation.Schema)));
        }

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

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

View on GitHub (pinned to dbf9771522)

Solutions

  1. Ensure every row in keyValues has exactly operation.KeyColumns.Length entries (the second dimension of the 2D array equals the keyColumns array length).
  2. Re-scaffold the migration so DeleteData arrays are regenerated for the current composite key.
  3. Use modelBuilder.Entity<T>().HasData(...) and remove rows there, letting EF scaffold the DeleteData consistently.
  4. Audit: assert keyValues.GetLength(1) == keyColumns.Length for each DeleteData.

Example fix

// before (composite key 2 columns, only 1 value):
migrationBuilder.DeleteData(
    table: "Members",
    keyColumns: new[] { "UserId", "GroupId" },
    keyValues: new object[,] { { 7 } });

// after (one value per key column):
migrationBuilder.DeleteData(
    table: "Members",
    keyColumns: new[] { "UserId", "GroupId" },
    keyValues: new object[,] { { 7, 3 } });
Defensive patterns

Strategy: validation

Validate before calling

static bool DeleteDataKeyShapeIsValid(string[] keyColumns, object[,] keyValues)
{
    return keyValues.GetLength(1) == keyColumns.Length;
}

// usage before calling migrationBuilder.DeleteData
if (!DeleteDataKeyShapeIsValid(keyColumns, keyValues))
    throw new InvalidOperationException("keyValues second dimension must equal keyColumns.Length");

Try / catch

try
{
    await dbContext.Database.MigrateAsync();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("number of key values") && ex.Message.Contains("data deletion"))
{
    logger.LogError(ex, "A DeleteDataOperation has a keyValues/keyColumns length mismatch; fix the migration.");
    throw;
}

Prevention

When it happens

Trigger: A migration calls migrationBuilder.DeleteData(keyColumns: new[] { "Id", "TenantId" }, keyValues: new object[,] { { 1 } }) where the inner dimension of keyValues does not match the keyColumns length. Happens after editing a generated migration (e.g. composite key) and dropping a key value, or scaffolding HasData removal for a composite-key entity incorrectly.

Common situations: Editing generated DeleteData calls for composite-key tables and miscounting. Removing a HasData seed row for a composite-key entity and then hand-editing the migration. Copy-paste errors in hand-authored migrations.

Related errors


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/ed25476e25319e00. Report an issue: GitHub.