dotnet/efcore · error · InvalidOperationException
The number of key column types ({typesCount}) doesn't match
Error message
The number of key column types ({typesCount}) doesn't match the number of key columns ({columnsCount}) for the data deletion operation on '{table}'. Provide the same number of key column types and key columns. What it means
Thrown inside GenerateModificationCommands(DeleteDataOperation, ...) in src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs:977 (message key DeleteDataOperationTypesCountMismatch). It throws InvalidOperationException when operation.KeyColumnTypes is non-null but its length differs from operation.KeyColumns.Length. KeyColumnTypes is an optional explicit type override; if supplied, it must align element-for-element with KeyColumns.
Source
Thrown at src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs:977
/// </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)));
}
var keyPropertyMappings = operation.KeyColumnTypes == null
? GetPropertyMappings(operation.KeyColumns, operation.Table, operation.Schema, model)
: null;
for (var i = 0; i < operation.KeyValues.GetLength(0); i++)
{View on GitHub (pinned to dbf9771522)
Solutions
- Make operation.KeyColumnTypes either null (types resolved from the model) or an array of exactly operation.KeyColumns.Length.
- Re-scaffold the migration to regenerate consistent keyColumnTypes.
- Map the table to an entity type so keyColumnTypes can be omitted entirely.
- Audit: for every i, KeyColumns[i] must pair with KeyColumnTypes[i].
Example fix
// before (2 key columns, 1 key type):
migrationBuilder.DeleteData(
table: "Members",
keyColumns: new[] { "UserId", "GroupId" },
keyColumnTypes: new[] { "int" },
keyValues: new object[,] { { 7, 3 } });
// after (aligned):
migrationBuilder.DeleteData(
table: "Members",
keyColumns: new[] { "UserId", "GroupId" },
keyColumnTypes: new[] { "int", "int" },
keyValues: new object[,] { { 7, 3 } }); Defensive patterns
Strategy: validation
Validate before calling
static bool DeleteKeyTypesAreValid(string[] keyColumns, string[]? keyColumnTypes)
{
return keyColumnTypes == null || keyColumnTypes.Length == keyColumns.Length;
}
// usage
if (!DeleteKeyTypesAreValid(keyColumns, keyColumnTypes))
throw new InvalidOperationException("keyColumnTypes.Length must equal keyColumns.Length (or be null)"); Try / catch
try
{
await dbContext.Database.MigrateAsync();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("number of key column types") && ex.Message.Contains("data deletion"))
{
logger.LogError(ex, "A DeleteDataOperation has a keyColumnTypes/keyColumns length mismatch; fix the migration.");
throw;
} Prevention
- Omit keyColumnTypes when an entity maps the table.
- When supplying keyColumnTypes, keep them in the same order and count as keyColumns.
- Re-scaffold migrations after key changes rather than hand-editing.
- Add a test asserting keyColumnTypes == null || keyColumnTypes.Length == keyColumns.Length.
When it happens
Trigger: A migration calls migrationBuilder.DeleteData with keyColumnTypes: set to an array whose length differs from keyColumns:. For example keyColumns: new[] { "Id", "TenantId" } with keyColumnTypes: new[] { "int" }. Common after hand-editing a migration and removing a key column but not its type.
Common situations: Manually adding keyColumnTypes and miscounting. Editing a model-less migration and forgetting a key type entry. Refactoring a composite key without updating the type array.
Related errors
- The number of key values ({valuesCount}) doesn't match the n
- The number of values ({valuesCount}) doesn't match the numbe
- The number of column types ({typesCount}) doesn't match the
- The data deletion operation on '{table}' is not associated w
- The number of key values ({valuesCount}) doesn't match the n
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/2470b014015e30a9.
Report an issue: GitHub.