dotnet/efcore · error · InvalidOperationException

The parameter ' ' cannot be added to the stored procedure '…

Error message

The parameter '{parameter}' cannot be added to the stored procedure '{sproc}' because another parameter with this name already exists.

What it means

Thrown when ValidateStoredProcedure iterates the parameters of a mapped sproc and finds two parameters with the same Name within a single stored procedure mapping. The validator maintains a HashSet<string> parameterNames per sproc and rejects the duplicate; sproc parameters must be uniquely named because EF builds a positional/named argument list keyed by name.

Solutions

  1. Inspect the sproc mapping and find both calls producing the same parameter Name; give them distinct names via the parameter-name overload: .HasParameter("foo_current", p => p.Foo) and .HasParameter("foo_original", p => p.Foo).
  2. If one of the duplicates is the row-count/output value, configure it as a rows-affected parameter/result column rather than a regular parameter.
  3. Remove the redundant HasParameter call entirely if both were intended to map the same property value.

Example fix

// before
entityType.UpdateUsingStoredProcedure("UpdateOrder",
    sp =>
    {
        sp.HasParameter(o => o.RowVersion); // produces "RowVersion"
        sp.HasOriginalValueParameter(o => o.RowVersion); // also "RowVersion" -> duplicate
    });

// after
entityType.UpdateUsingStoredProcedure("UpdateOrder",
    sp =>
    {
        sp.HasParameter("RowVersion_Current", o => o.RowVersion);
        sp.HasOriginalValueParameter("RowVersion_Original", o => o.RowVersion);
    });
Defensive patterns

Strategy: validation

Validate before calling

// Assert unique parameter names per sproc mapping.
foreach (var et in model.GetEntityTypes())
{
    foreach (var sproc in new[] { et.GetInsertStoredProcedure(), et.GetUpdateStoredProcedure(), et.GetDeleteStoredProcedure() })
    {
        if (sproc == null) continue;
        var names = sproc.Parameters.Select(p => p.Name).ToList();
        var dupes = names.GroupBy(n => n).Where(g => g.Count() > 1).Select(g => g.Key);
        foreach (var d in dupes)
            Console.WriteLine($"Duplicate parameter '{d}' on {sproc.Name}");
    }
}

Prevention

When it happens

Trigger: Two .HasParameter(...) / .HasOriginalValueParameter(...) / .HasResultColumn(...) calls produce the same parameter Name on the same InsertUsingStoredProcedure / UpdateUsingStoredProcedure / DeleteUsingStoredProcedure. Common when HasParameter(p => p.Id) is combined with HasOriginalValueParameter(p => p.Id) without setting distinct names, or when a row-count parameter collides with a property parameter name.

Common situations: Copy-pasting parameter config across insert/update/delete sproc builders; mapping both current value and original value of the same property without specifying separate parameter names; an automatically generated concurrency-token parameter colliding with an explicit one.

Related errors


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

Appendix: source

Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:782

                                            property.GetAfterSaveBehavior()));
                                }

                                break;

                            case StoreObjectType.DeleteStoredProcedure:
                                break;

                            default:
                                Check.DebugFail("Unexpected stored procedure type: " + storeObjectIdentifier.StoreObjectType);
                                break;
                        }
                    }
                }
            }

            if (!parameterNames.Add(parameter.Name))
            {
                throw new InvalidOperationException(
                    RelationalStrings.StoredProcedureDuplicateParameterName(
                        parameter.Name, storeObjectIdentifier.DisplayName()));
            }

            if (parameter.PropertyName == null)
            {
                continue;
            }

            switch (storeObjectIdentifier.StoreObjectType)
            {
                case StoreObjectType.InsertStoredProcedure:
                case StoreObjectType.UpdateStoredProcedure:
                    if (parameter.Direction != ParameterDirection.Input
                        && !storeGeneratedProperties.Remove(property!.Name))
                    {
                        if (sproc.Parameters.Any(p => p.PropertyName == property.Name
                                && p.ForOriginalValue != parameter.ForOriginalValue

View on GitHub (pinned to 3a2006ef56)